本文共 8488 字,大约阅读时间需要 28 分钟。
前篇中,我们介绍了 Redux ,对 Store 、 Action 、Reducer 有了初步的了解。并配合 react-redux ,梳理了其工作流程,结合使用了 Provider 、 connect() 。
接下来,我们完成开篇任务中的最后一项,过滤显示 TODO 。http://www.jianshu.com/p/611fdc455e37
源码:
我们所做任务如下:
state
:todos
平级,做为当前过滤条件。TodoFilterComponent
:All
、Undo
、Finish
,并接收一个属性为当前过滤条件,过滤按钮与当前过滤条件相同时,过滤按钮不可点击。HomeContainer
:Action
:ActionCreator
生成设置当前过滤条件的 Action
。Reducer
: 1、添加新初始 state
ReactReduxDemo/app/index.js
文件,修改如下:
import React, { Component } from 'react';import { View, StyleSheet,} from 'react-native';import { createStore } from 'redux'; import { Provider } from 'react-redux'; import reducers from './reducers/index'; import HomeContainer from './containers/home.container';// 这是初始数据const initState = { todos: [ { title:'吃早饭',status:true}, { title:'打篮球',status:false}, { title:'修电脑',status:false}, ], filter: 'All', // 'All'|'Undo'|'Finish' // 添加新的初始 `state`};let store = createStore(reducers, initState);export default class RootWrapper extends Component{ render(){ return (); }}const styles = StyleSheet.create({ wrapper: { flex: 1, marginTop: 20, },});
2、创建子组件 TodoFilterComponent
新建文件 ReactReduxDemo/app/components/todo-filter.component.js
, 如下:
import React, { Component } from 'react';import { View, Text, TouchableOpacity, StyleSheet,} from 'react-native';export default class TodoFilterComponent extends Component{ constructor(props){ super(props); } filterTodo(filter){ this.props.filterTodo && this.props.filterTodo(filter); } renderFilter(filter){ if(filter==this.props.filter){ return ({filter} ); } return ({this.filterTodo(filter)}}> ); } render(){ return ({filter} {this.renderFilter('All')} {this.renderFilter('Undo')} {this.renderFilter('Finish')} ); }}const styles = StyleSheet.create({ wrapper: { flexDirection: 'row', paddingLeft: 20, paddingTop: 20, }, filter: { marginRight: 20, textDecorationLine: 'underline', }, filterCurrent:{ color: 'gray', textDecorationLine: 'none', },});
3、容器组件HomeContainer
我们在其中引入子组件TodoFilterComponent
,并添加过滤方法,此方法的功能为设置当前过滤条件。
ReactReduxDemo/app/containers/home.container.js
文件,修改如下:
import React, { Component } from 'react';import { View, Text} from 'react-native';import { connect } from 'react-redux';import { changeTodoStatus, addNewTodo, filterTodoList } from '../actions/index'; // 引入 actionimport TodoFormComponent from '../components/todo-form.component';import TodoListComponent from '../components/todo-list.component';import TodoFilterComponent from '../components/todo-filter.component'; // 引入子组件class HomeContainer extends Component{ constructor(props){ super(props); } addTodo(text){ let { dispatch } = this.props; dispatch(addNewTodo(text)); } toggleTodo(index){ let { dispatch } = this.props; dispatch(changeTodoStatus(index)); } filterTodo(filter){ let { dispatch } = this.props; // 从 props 里解构出 dispatch dispatch(filterTodoList(filter)); // 执行过滤方法 } render(){ return (); }}// 基于全局 state ,哪些 state 是我们想注入的 propsfunction mapStateToProps(state){ return { todoList: state.todos, currentFilter: state.filter, // 注入新的 state 到 props }}export default connect(mapStateToProps)(HomeContainer); { this.addTodo(text)}} /> { this.toggleTodo(index)}} /> { this.filterTodo(filter)}} /> // 渲染子组件(注释会报错,请删除注释)
4、修改 Action
添加新的 action
类型,新的 action
创建函数。
ReactReduxDemo/app/actions/index.js
文件,修改如下:
/*********************************** action 类型常量 *************************************//** * 更改 TODO 状态 * @type {String} */export const TOGGLE_TODO_STATUS = 'TOGGLE_TODO_STATUS';export const ADD_NEW_TODO = 'ADD_NEW_TODO';export const SET_FILTER = 'SET_FILTER'; // 添加新的 action 类型/*********************************** action 创建函数 *************************************//** * 更改 TODO 状态 * @param {Number} index TODO索引 * @return {Object} action */export function changeTodoStatus(index){ return {type: TOGGLE_TODO_STATUS, index};}export function addNewTodo(text){ return {type: ADD_NEW_TODO, text};}export function filterTodoList(filter){ // 添加新的 action 创建函数 return {type: SET_FILTER, filter};};
5、修改 Reducer
引用新的action
类型,添加新的reducer
函数,并在 combineReducers
中使用。
ReactReduxDemo/app/reducers/index.js
文件,修改如下:
import { combineReducers } from 'redux';import { TOGGLE_TODO_STATUS, ADD_NEW_TODO, SET_FILTER } from '../actions/index'; // 引入 action ,使用 action 类型常量function todoList(state=[], action){ switch(action.type){ case TOGGLE_TODO_STATUS: var todo = state[action.index]; return [ ...state.slice(0, action.index), Object.assign({}, todo, { status: !todo.status }), ...state.slice(action.index + 1) ]; case ADD_NEW_TODO: return [ ...state, { title: action.text, status: false, } ]; default : return state; }}function setFilter(state='', action){ // 定义了新的 reducer switch(action.type){ case SET_FILTER: return action.filter; default : return state; }}const reducers = combineReducers({ todos: todoList, filter: setFilter, // 添加了新的 reducer combine});export default reducers;
运行项目,是否显示出了过滤按钮呢?点击试试看,能否过滤?(暂时还不可以,我们需要写方法对数据进行过滤)
todo 列表有了,当前过滤条件也可以设置了。这里,我们需要完成根据当前过滤条件对 TODO 列表进行过滤显示。
我们知道,TODO 列表的显示,是根据容器组件HomeContainer
给的数据来显示的,它并不知道数据的具体来源,给它什么数据它就显示什么数据(这也正是我们想要的功能)。
我们就会想到,将容器组件HomeContainer
的 TODO 列表数据做修改,是不是就可以了呢?是的,确实是这样。
我们来看容器组件HomeContainer
部分代码
// 基于全局 state ,哪些 state 是我们想注入的 propsfunction mapStateToProps(state){ return { todoList: state.todos, // <---- 这里就是给子组件展示的数据 currentFilter: state.filter, }}
我们将其做一些修改过滤,就OK了。
ReactReduxDemo/app/containers/home.container.js
文件,修改如下:
import React, { Component } from 'react';import { View, Text} from 'react-native';import { connect } from 'react-redux';import { changeTodoStatus, addNewTodo, filterTodoList } from '../actions/index'; import TodoFormComponent from '../components/todo-form.component';import TodoListComponent from '../components/todo-list.component';import TodoFilterComponent from '../components/todo-filter.component'; class HomeContainer extends Component{ constructor(props){ super(props); } addTodo(text){ let { dispatch } = this.props; dispatch(addNewTodo(text)); } toggleTodo(index){ let { dispatch } = this.props; dispatch(changeTodoStatus(index)); } filterTodo(filter){ let { dispatch } = this.props; dispatch(filterTodoList(filter)); } render(){ return (); }}const getFilterTodos = (todos, filter) => { // 定义 TODO 过滤方法,返回新的数据 switch (filter) { case 'All': return todos; case 'Undo': return todos.filter( todo => !todo.status); case 'Finish': return todos.filter( todo => todo.status); default: throw new Error('Unknown filter: ' + filter); }}// 基于全局 state ,哪些 state 是我们想注入的 propsfunction mapStateToProps(state){ return { todoList: getFilterTodos(state.todos, state.filter), // 注入props时,调用 TODO 过滤方法 currentFilter: state.filter, }}export default connect(mapStateToProps)(HomeContainer); { this.addTodo(text)}} /> { this.toggleTodo(index)}} /> { this.filterTodo(filter)}} />
运行项目,是否可以对 TODO 列表进行过滤了呢?恭喜你!!
到目前为止,我们的 ReactNative + Redux 开发示例告一小段落。
后面会有中间件、异步的的使用方法。
转载地址:http://ogeni.baihongyu.com/