1.基础原则
1).单项数据流
2).唯一数据源
保持唯一的Store,所有组件的数据源就是Store上的状态
3).保持状态只读
UI=render(state),虽然通过state驱动组件渲染,但改变状态的方法不是去修改状态上的值,而是创建一个新的状态对象返回给redux,由redux完成新的状态的组装
4).数据改变只能通过纯函数完成
redux中reducer的函数签名如下:
reducer(state,action)
第一个state是当前状态,第二个action是接收到的action对象。
reducer的作用就是根据state和action的值产生一个新的对象返回。因为reducer必须是一个纯函数,所以返回值完全由传进来的参数state和action决定。
2.关于扩展操作符1
return { ...state, [counterCaption]: state[counterCaption] + 1 }
这种扩展操作符表示把state中的所有字段扩展开,然后后面对[counterCaption]值对应的字段会赋上新值。
用扩展操作符的目的:
1).如果创造一个新的state把传进来的state的值赋值上去,然后修改新的state,这样写会显得代码冗长不如扩展操作符简洁清晰。
2).扩展操作符可以在一对{}符号中把一个对象展开,这样,在{}中后面的部分的字段值,可以覆盖前面展开的部分。
3.获取在store上存储状态1
store.getState()
能够获得store上存储的所有状态。但一般一个组件只需要用到部分返回状态的数据,可以自己再用一个函数单独封装一下。
4.组件拆分
在redux框架下,一个react组件要完成两个功能
1).读取store的状态,初始化组件;监听store的状态是否改变;需要更新store的时候派发action对象
2).根据当前props和state,渲染出用户界面
如果一个组件完成以上两个功能逻辑稍显复杂,于是拆分成一个子组件和一个父组件。处于外层负责和store打交道的叫容器组件也叫聪明组件;内层的叫展示组件也叫傻瓜组件。
傻瓜组件就是一个纯函数,根据props产生结果。这样一来,傻瓜组件就不需要状态了,只需要根据props渲染。至于state就交给外层的聪明组件去处理,然后把状态用props传给傻瓜组件。
傻瓜组件的示例:1
2
3
4
5
6
7
8
9
10
11
12class Counter extends Component {
render() {
const {caption, onIncrement, onDecrement, value} = this.props;
return (
<div>
<button onClick={onIncrement}>+</button>
<button onClick={onDecrement}>-</button>
<span>{caption} count : {value}</span>
</div>
);
}
}
对于无状态组件可以进一步缩减1
2
3
4
5
6
7
8
9
10function Counter (props) {
const {caption, onIncrement, onDecrement, value} = props;
return (
<div>
<button onClick={onIncrement}>+</button>
<button onClick={onDecrement}>-</button>
<span>{caption} count : {value}</span>
</div>
);
}
5.context&connect
context是一个很好的办法去解决不让组件直接引用store也不用过props层层传递就可以获取store的状态。
只需要最顶层的组件提供包含store和context,那就覆盖了整个应用的所有组件。
拆分组件和context现在都可以由react-redux库来完成这些工作。
至于connect,connect是用来链接容器组件和傻瓜组件的。
例如这样的写法:1
export default connect (mapStateToProps, mapDispatchToProps)(Counter);
这里connect接受两个参数,一个是mapStateToProps一个是mapDispatchToProps,因为返回结果依旧是一个函数所以才可以在后面又加一个圆括号,把connect函数执行的结果立刻执行。最后这个参数就是傻瓜组件。
至于这个connect函数具体的工作是什么,其实就是把store上的状态转化为傻瓜组件的props,其次就是把傻瓜组件中的用户动作转化为派给store的动作。