Redux TodoList例子解析[自己胡编乱造]

Redux源码中包含的例子:https://github.com/reactjs/redux/tree/master/examples
这里解析的是Todos例子,直接切入正题好了。在todos.js中,state的默认状态为state: [],在visibilityFilter.js中,state的默认状态为state: ‘SHOW_ALL’,当两个reducer合为一个reducer后,如下代码,这时state的状态为state: {todos: [], visibilityFilter: ‘SHOW_ALL’}

1
2
3
4
const todoApp = combineReducers({
todos,
visibilityFilter
});

这里的reducers由两部分组成,包括todos和visibilityFilter,其中todos里面包含两个action类型,一个是添加todo[ADD_TODO],一个是切换todo的完成状态[TOGGLE_TODO];visibilityFilter里面包含一个action类型,设置过滤器[SET_VISIBILITY_FILTER],画了个简单的结构图看的更直接一点。

在actions中包含几个方法,用来传递action类型、过滤值、id等,利用dispatch触发reducer,实现状态的改变,从而渲染出不同的todo列表,接下来会从下面几点做下简单的分析,给actions画了个简单的结构图。

1.添加todo。当在输入框写入内容后,点击“Add Todo”按钮,列表多出一条数据,这里首先讲下添加todo这一过程。在AddTodo.js中,样式不关注,看它在表单提交中做了哪步关键操作,观察代码是dispatch(addTodo(input.value)),其中addTodo(input.value)调用的是actions中的方法,此时action为一个新的对象:{type: ‘ADD_TODO’, id: 1, text: ‘内容’},接着通过dispatch(…),开始触发reducer,即todoApp,根据action的类型[action.type]返回新的状态,即state变为{todos: [{type: ‘ADD_TODO’, id: 1, text: ‘内容’, completed: false}], visibilityFilter: ‘SHOW_ALL’}。当继续添加todo,执行上述步骤,state继续更新,todoList也随着todo的增加而增加。

2.todo列表。根据state中的todos以及visibilityFilter过滤状态判断todo列表的输出内容。在VisibleTodoList.js中,用到connect将两个组件连接在一起,其中TodoList为一个UI组件,UI组件里面用到的属性方法,均由connect方法中两个参数提供[mapStateToProps,mapDispatchToProps]
其中mapStateToProps方法,理解其命名含义,其实不难理解,将state对象作为数据传给UI组件使用,如

1
2
3
constmapStateToProps= (state) => ({
todos:getVisibleTodos(state.todos, state.visibilityFilter)
})

那么UI组件TodoList就可以用todos作为属性,即可以根据属性todos遍历出todo列表。getVisibleTodos(…)该方法是为了计算得出todos的内容,比如是要渲染出已完成/进行中的列表等,该方法会对传进去的state.visibilityFilter进行筛选。

对于connect中的另一个参数mapDispatchToProps,用来建立 UI 组件的参数到store.dispatch方法的映射。mapDispatchToProps可以是个函数,也可以是个对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 函数表示,如果mapDispatchToProps是一个函数,会得到dispatch和ownProps(容器组件的props对象)两个参数。
const mapDispatchToProps = (
dispatch,
ownProps
) => {
return {
onClick: () => {
dispatch({
type: 'SET_VISIBILITY_FILTER',
filter: ownProps.filter
});
}
};
}
// 对象表示
constmapDispatchToProps= {
onTodoClick:toggleTodo
}

这时候UI组件TodoList拥有onTodoClick方法,即toggleTodo(…),前面通过mapStateToProps拿到的todos值遍历出列表,也就是根据todos循环渲染出Todo组件内容,当点击列表项时,会改变todo的状态,即活动变为完成,完成变为活动,这时候调用的是onTodoClick方法,即actions中的toggleTodo方法,这是action为一个新的对象:{type: ‘TOGGLE_TODO’, id: 1},通过dispatch,根据action的类型返回新的状态,即state变为{todos: [{type: ‘ADD_TODO’, id: 1, text: ‘内容’, completed: true}], visibilityFilter: ‘SHOW_ALL’},这时列表项根据completed判断样式显示,当再次点击原列表项后,completed状态变为false,这时样式又发生改变。

3.列表过滤。过滤包括三个状态:全部、进行、完成,通过FilterLink组件渲染出该tab栏,在FilterLink组件中,同样通过connect将Link组件与本身连接起来,那么根据mapStateToPropsmapDispatchToProps两个函数,使Link拿到active以及onclick两个属性,从而判断是否拥有链接效果。

其中mapStateToProps函数中,用到ownProps参数,该参数由Footer组件提供,它是一个对象:{filter: ‘SHOW_ALL’, children: ‘ALL’}。然后根据ownProps.filter === state.visibilityFilter判断,从而得出该tab标签是否有链接效果,由于state.visibilityFilter默认为‘SHOW_ALL’,所以默认是显示所有列表项。

那么当tab栏中的其他标签被点击,就会用到mapDispatchToProps提供的onClick方法,触发dispatch(setVisibilityFilter(ownProps.filter)),这时候setVisibilityFilter拿到最新的过滤状态,比如‘SHOW_COMPLETED’,类型为‘SET_VISIBILITY_FILTER’,那么通过dispatch(…)通知reducer得到最新的过滤状态,也就是‘SHOW_COMPLETED’,这时总的状态state发生改变:{todos: [{…},{…}], visibilityFilter: ‘SHOW_COMPLETED’},那么列表的显示也会因为状态state的变化重新渲染,这里就调用了VisibleTodoList组件中的getVisibleTodos()方法得到最新的todos值,从而过滤出不同的列表。

以上就是对这个小例子的简单解析,看不懂只能说明我写的文稿有问题,会继续好好文笔描述。如果哪里有错误,也请指出,多多包涵。

参考资料:Redux 入门教程(三):React-Redux 的用法