在 Redux 中,对 state 进行计算重新返回的方法通常叫做 reducer,如果 state 比较简单,只在一个 reducer 中也可以清晰的看明白数据处理过程,但 redux 通常用来处理复杂的应用程序,state 结构通常比较庞大,结构比较复杂,如果都写到一个方法里面,非常不便于维护,此时就需要对 reducer 进行拆分成多个子 reducer。
combineReducers
redux 提供的 combineReducers 用于将多个 reducer 合并成一个 reducer,该方法接收一个 Object 对象。
1 2 3 4
| Object { prop1: reducerProp1, prop2: reducerProp2, }
|
如上一个 Object 表示合并之后得到的 reducer 将处理两个属性 prop1 和 prop2,处理函数分别是 reducerProp1 和 reducerProp2。
state
1 2 3 4 5 6 7 8 9 10
| { user: { name: "Michael Cai", age: 0 }, work: { name: "IT", years: 0 } }
|
假设有如上一个 state 结构,user 表示用户,work 表示工作,接下来需要做的就是把 user 和 work 拆分出来放到不同的 reducer 中去处理更新 state。
reducer
分别定义处理 user 和 work 的 reducer。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import {combineReducers} from 'redux'; function userName(state = '', action) { if (action.type == 'USER_SET_NAME') { return action.name; } return state; } function userAge(state = 18, action) { if (action.type == 'USER_SET_AGE') { return action.age; } return state; } const user = combineReducers({ name: userName, age: userAge });
|
上面的代码定义了 user 的两个属性的更新处理函数,这两个属性的更新,也把它们给拆分开了,并没有放到一个整体的更新 user 对象的方法里面去更新。
下面是更新 work 的流程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function workName(state = 'gwy', action) { if (action.type == 'WORK_SET_NAME') { return action.name; } return state; } function workYears(state = 0, action) { if (action.type == 'WORK_SET_YEARS') { return action.years; } return state; } const work = combineReducers({ name: workName, years: workYears });
|
定义好子 reducer 后,再次通过 combineReducers 方法合并上面定义的两个 reducer :
1 2 3 4
| const reducer = combineReducers({ user, work });
|
渲染页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| import {createStore} from 'redux'; import React from 'react'; import ReactDOM from 'react-dom'; import {reducer} from './reducer.js'; const store = createStore(reducer, default_state); const App = React.createClass({ render: function () { return <div> <div> <button onClick={()=> { store.dispatch({'type': 'USER_SET_NAME', name: 'James'}) }}>SetUserName</button> <span>{store.getState().user.name}</span> </div> <div> <button onClick={()=> { store.dispatch({'type': 'USER_SET_AGE', age: 32}) }}>SetUserAge</button> <span>{store.getState().user.age}</span> </div> <div> <button onClick={()=> { store.dispatch({'type': 'WORK_SET_NAME', name: 'Android'}) }}>SetWorkName</button> <span>{store.getState().work.name}</span> </div> <div> <button onClick={()=> { store.dispatch({'type': 'WORK_SET_YEARS', years: 4}) }}>SetWorkAge</button> <span>{store.getState().work.years}</span> </div> </div> } }); const render = ()=> { ReactDOM.render(<App />, document.getElementById('root')); }; render(); store.subscribe(render);
|
应用程序可以分别设置 work.name,work.years,user.name,user.age;
createStore() 方法还可以直接传入一个默认的 state;
1 2 3 4 5 6 7 8 9 10
| const default_state = { user: { name: 'Michael Cai', age: 26 }, work: { name: 'gwy', years: 0 } };
|
如果不传入默认的 state,则在 reducer 函数定义时,需要定义对应的默认值,就像上面定义的 workName(),userName() 中 state 参数都赋予了默认值;
More
除了使用 redux 提供的 combineReducers 之外,也可以自己实现,实际上 combineReducers 处理之后的 reducer 就像是下面这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| const userReducer = (state = {name: '', age: 0}, action) => { return { name: userName(state.name, action), age: userAge(state.age, action) } }; const workReducer = (state = {name: '', age: 0}, action) => { return { name: workName(state.name, action), age: workYears(state.age, action) } }; const reducer = (state = {}, action) => ({ user: userReducer(state.user, action), work: workReducer(state.work, action) });
|