这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战
Redux
官网:redux.js.org/
创建一个Redux项目用Nodejs调试
创建身份证
npm init
安装依赖
npm install --save redux
创建app.js
var redux = require("redux");
//创建一个函数,叫做reducer。
const reducer = (state = {"a" : 10} , action) => {
if(action.type == "ADD"){
return {
"a" : state.a + 1
}
}else if(action.type == "MINUS"){
return {
"a" : state.a - 1
}
} else if (action.type == "PINGFANG") {
return {
"a" : state.a * state.a
}
}
return state;
}
//根据reducer函数创建store
const store = redux.createStore(reducer);
//得到store中的a
console.log(store.getState().a);
//发出ADD命令
store.dispatch({"type" : "ADD"}); //10+1
store.dispatch({"type" : "ADD"}); //11+1
store.dispatch({"type" : "ADD"}); //12+1
//得到store中的a
console.log(store.getState().a); //13
//发出减法命令
store.dispatch({"type" : "MINUS"}); // 13-1
//得到store中的a
console.log(store.getState().a); // 12
store.dispatch({ "type": "PINGFANG" }); //12*12
//得到store中的a
console.log(store.getState().a); //144
当dispatch 发出后 store变化了,而试图没有更新,需要使用订阅subscribe方法
1、 在组件内的 componentDidMount 声明周期内 强制刷新
componentDidMount(){
store.subscribe(()=>{
this.forceUpdate()
})
}
2、在入口文件中配置 subscribe,订阅后 重新 执行render
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import store from './store'
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
)
store.subscribe(()=>{
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
)
})
使用redux 检查点
- createStore 创建store
- reducer 初始化、修改状态函数
- getState 获取状态值
- dispatch 提交更新
- subscribe 变更订阅
可预测状态容器
借助Redux,你可以控制状态改变的时间、原因和方式。
Store: 单一数据源
步骤:引入createStore函数、引入reducer统领文件、创建store、试着弹出一个a。
store有下面的责任: | 持有app的state | 允许通过getState()得到state | 允许通过dispatch来改变state | 只能有1个store在你的app中。 | 当你想切分你的数据逻辑,你应该考虑拆分reducer而不是拆分store。 | 创建一个reducer很简单,使用combineReducers()可以轻松合并多个reducer到一个。并且传入createStore()中 |
---|
得到Store的State的值,需要使用store.getState().a
复杂的state
state 可能是复杂的结构,此时写在行内不好看,可以提炼为变量(常量)
var redux = require("redux");
//初始state
const initState = {
students : [
{"id": 1, "name": "小明" , "age" : 12},
{"id": 2, "name": "小强" , "age" : 14},
{"id": 3, "name": "小钢炮" , "age" : 13}
]
}
//reducer
const reducer = (state = initState, action) => {
.........
.........
}
reducer 纯函数
记住4个no: | No surprises. No side effects. No API calls. No mutations. Just a calculation. | 没有惊喜、没有副作用、没有API调用、没有改变传入的参数。就是一个计算。 |
---|
纯函数是函数式编程的概念,必须遵守以下一些约束:
- 不得改写参数
- 不能调用写I/O的API
- 不能调用Date.now() 或者Math.random()等不纯的方法,因为每次得到不一样的结果
Reducer是纯函数,就可以保证同一的state,必定得到同样的View,Reducer函数里面不能改变State,必须返回一个全新的对象。
一个函数会有很多reducer,所以要有一个index.js作为“统领文件”
dispatch和action
store.disptch()
action
- Action就是一个信息的载荷体,从APP(逻辑层、视图层)送到你的store中(数据层)。
- action是store唯一的信息的来源。
- action需要被dispatch()函数派发。
- action是纯的、扁平的JavaScript对象。
- action必须有一个type属性,type属性指示了这个action是干嘛的。
action就是一个有type属性的JSON:
{"type" : "ADD"}
payload 载荷
action不仅有type属性,其他的属性,叫做载荷(payload)
combineReducers 合并多个reducer
注意:
- 访问值的时候,多个一个命名空间
- 改变值的时候,没有命名空间
//要合并reducer,因为任何项目只能有一个reducer。
const reducer = redux.combineReducers({
counterReducer ,
studentReducer
});
//store,不管项目有多大,一定只有一个store
const store = redux.createStore(reducer);
//注意,访问值的时候,多了一个命名空间
console.log(store.getState().counterReducer.a);
//但是,改变值的时候,没有命名空间
store.dispatch({ "type" : "ADD"});
store.dispatch({ "type" : "ADD"});
store.dispatch({ "type" : "ADD"});
//注意,访问值的时候,多了一个命名空间
console.log(store.getState().counterReducer.a);
React和Redux配合使用
所有的数据要保存在store中
配置和使用
- 先配置好webpack+react那一套 安装依赖
npm install --save redux
npm install --save react-redux
- react-redux 是官方的“粘合剂”
-
- 这个粘合剂就提供了两个东西:Provider组件、connect函数。
- Provider from react-redux
main.js
import React from "react";
import ReactDOM from "react-dom";
import {createStore} from "redux";
import {Provider} from "react-redux";
import App from "./App";
import reducer from "./reducers";
//创建store
const store = createStore(reducer);
ReactDOM.render(
<Provider store={store}>
<App></App>
</Provider>
,
document.getElementById("app")
);
app.js
- import { connect } from "react-redux"
import React, { Component } from 'react';
import { connect } from "react-redux";
class App extends Component {
constructor(){
super();
}
render() {
return (
<div>
<h1>根组件{this.props.a}</h1>
<button onClick={()=>{
this.props.add();
}}>按我加1</button>
</div>
)
}
}
//connect 函数 有两个参数和需要连接的组件App
export default connect(
({counterReducer}) => ({
a : counterReducer.a
}),
(dispatch) => ({
add(){
dispatch({"type" : "ADD"})
}
})
)(App);
Provider
- Provider 是组件,在main.js入口文件中用一次
- connect 是函数,哪个组件要“通天”要数据,哪个组件就要connect装饰一下。
- Provider的机理是使用context上下文机理。
Provider使用起来很简单,引包之后,包裹app,注意store属性:
import {Provider} from "react-redux";
ReactDOM.render(
<Provider store={store}>
<App></App>
</Provider>
,
document.getElementById("app")
);
connect装饰器
语法:
connect(mapStateToProps , mapDispatchToProps)(类名字)
- 组件要更新视图,只有两种手段:
-
- 组件自己的state改变
-
- 传入组件的props改变
- 全局store数据变化了,组件视图要更新。
- store中的数据,要被“装饰”到组件上,成为组件的props。
组件要被connect()()装饰一下,才能暴露:
- 第一个()内写如何装饰,第二个()内写装饰谁。
-
- 第一个()有两个参数 mapStateToProps和mapDispatchToProps
mapStateToProps(state, ownProps)
- mapStateToProps 是一个函数,用于建立组件跟store的state的映射关系,它传入两个参数,结果一定返回一个object。
- mapStateToProps 可以不传,如果不传,组件不会监听store的变化,也就是说Store的更新不会引起UI的更新。
export default connect(
({counterReducer}) => ({
a : counterReducer.a
})
)(App);
这个函数的形参中罗列reducer的名字,要用大括号包裹,函数返回值是一个对象,所以必须有一个小括号对。
这个返回的对象的所有的键,将成为组件的props。
<h1>根组件{this.props.a}</h1>
mapDispatchToProps
mapDispatchToProps 用于建立组件跟store.dispatch的映射关系,可以是一个objeft,也可以传入一个函数
export default connect(
({counterReducer}) => ({
a: counterReducer.a
}),
(dispatch) => ({
add(){
dispatch({"type" : "ADD"})
}
})
)(App);
logger -- 输出器的安装
- 一装一引一配 安装依赖
npm install --save redux-logger
main.js中的配置
import React from "react";
import ReactDOM from "react-dom";
import {createStore , applyMiddleware} from "redux";
import {Provider} from "react-redux";
import logger from "redux-logger";
import App from "./App";
import reducer from "./reducers";
//创建store
const store = createStore(reducer , applyMiddleware(logger));
ReactDOM.render(
<Provider store={store}>
<App></App>
</Provider>
,
document.getElementById("app")
);
今后就能在任何一次dispatch发出的时候,看见控制台的自动输出:能够看见改变前的state、发出的action、改变之后的state。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!