react是单向传递数据的框架,试想在一个相对复杂的应用里面,组件的层级比较多,需要用到数据的地方还有很多,我们的数据可能需要一层一层传递,这样是非常不方便的。还有极端的情况是
子组件1的数据改变后影响子组件2的渲染,这个时候只使用react是肯定不行的,一大串的传递会让人崩溃。所以,在一个功能比较复杂的app下,数据管理会用到redux。
如图所示,redux包括下面几个关键性要素:
Store
顾名思义,翻译为仓库,储存数据的地方,这里可以把它比喻为一个图书馆管理员,能提供的是当前藏书状态
Action
由调用redux仓库的事件发出,可以想象为有人借书,或者管理员往图书馆里添加书,这些操作都会告诉管理员
Reducer
上面说到有借书或者还书的行为,那么这些动作如何改变图书馆藏书的状态,就需要Reducer来计算了,同时反馈给store,这个时候得到的就是新的仓库状态了。
Component
这里指的是和仓库里的数据直接相关的一些组件,它们可以获得当前图书的信息,也可以去发出action(借书
还书)
下面说说基本的用法:
- 引入redux,创建仓库
const store = createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__())
注意这里第二个参数是添加了redux dev tool,为了方便观察数据添加的
- 编写reducer,总而言之就是各种规则以及初始的状态
const defaultstate = {
num:0
}
export default function (state=defaultstate,action) {
if (action.type==='add') {
return Object.assign(state,{
num:state.num+1
})
}else if(action.type==='sub'){
return Object.assign(state,{
num:state.num-1
})
}else{
return state
}
}
这里有个细节,我们没有办法直接改变store里面state里的值,而是返回一个新的state,这里拷贝对象的时候我用的是Object.assign(),也可以通过JSON来拷贝
- 为需要的component派发action,然后在相应的地方获取所需值
let num = store.getState().num
let addNum = function (dispatch) {
let action = {
type:'add'
}
store.dispatch(action)
}
let subNum = function (dispatch) {
let action = {
type:'sub'
}
store.dispatch(action)
}
class App extends Component {
render() {
return (
<div className="App">
{num}
<button onClick={addNum}>+</button>
<button onClick={subNum}>-</button>
</div>
);
}
}
这里store有两个主要的方法,getState获取当前的state,dispatch发送action,进行到这里的时候我们发现页面上的数字并没有和我们期望的那样发生改变,但是检查页面发现实际上state发生了变化
这是因为不是react组件内部发生state改变,组件是无法检测到变化从而自动更新UI的,所以我们需要最后一步
- 订阅变化,这里我们调整一下代码,将store抽离出来,然后在监听到store的state发生变化时,重新渲染页面,这样就实现了redux实现简单的数据管理。
store.subscribe(function(){
ReactDOM.render(<App num={store.getState().num}/>, document.getElementById('root'));
})
目录结构以及代码可参考https://github.com/SNJiang1992/react-demo/tree/master/src
(完)