前言
Redux 是一个状态管理框架,通常与 React 结合使用,来实现 React 的状态集中统一化管理。但是与 Vuex 不同的是,Redux 也可以独立使用。并不专职为 React 服务。而 Vuex 主要是为 Vue 专门制定的状态管理工具。
在使用前执行npm install redux react-redux
下载 Redux。
案例需求
实现一个 todoList (代办事项管理),包含的功能有:
- 添加待办事项;
- 编辑待办事项状态(将待办事项置为已完成或者未完成);
- 删除待办事项;
- 查询待办事项(按状态已完成/未完成/所有查询)。
实现思路
一共分为三个组件实现该功能。
TodoList.js 为核心组件父组件,提供添加待办事项的方法。
TodoItem.js 为任务项组件,渲染任务项视图,提供修改待办事项状态及删除任务的方法。
FilterItem.js 为过滤器组件,渲染过滤项视图。提供筛选待办事项的方法。
第一步:定义 Action
action 定义用户行为类型以及该行为所需要的参数。在整个 todolist 程序中,抽象出来的用户行为有:用户添加待办事项、用户改变待办事项状态、用户删除待办事项、用户筛选待办事项。
let count = 0;
let actions = {
//添加任务
addTodo: (text)=>{
return {type: 'add', payload:{text:text,id:++count,done:false}};
},
//删除任务
delTodo: (index)=>{
return {type: 'del', index};
},
//修改任务状态
changeStatus:(item)=>{
return {type: 'change', item};
},
//过滤任务列表
onFilter:(flag)=>{
return {type: 'filter', flag};
}
};
export default actions;
第二步:定义 Reducer
reduce 表示根据用户行为,响应不同的状态,然后根据状态更新视图。在整个 todolist 程序中,抽象出来的响应状态有:
- 新增/删除/更改代办事项之后更新待办事项列表,定义 todosReducers;
const todosReducer = (state = [],action)=>{
switch (action.type) {
case 'add':
state = [...state, action.payload];
return [...state];
case 'del':
state.splice(action.index,1);
return [...state];
case 'change':
action.item.done = !action.item.done;
return [...state];
default:
return state;
}
};
export default todosReducer;
- 根据用户的筛选条件查询出符合条件的待办事项列表,定义 filterReducers。
const filterReducer = (state ="all", action)=>{
switch (action.type) {
case 'filter':
if(action.flag == 'all'){
state = 'all';
};
if(action.flag == 'completed'){
state = true;
};
if(action.flag == 'uncompleted'){
state = false;
};
return state;
default:
return state;
}
};
export default filterReducer;
第三步:整合 Reducer
通过 combineReducers 方法将单个的 Reducer 整合到一起,定义allReducers。
import {combineReducers} from 'redux';
import filterReducer from './filterReducer';
import todosReducer from './todosReducer';
const allReducers = combineReducers({filter:filterReducer,todos:todosReducer});
export default allReducers;
第四步:定义 Store
store 是储存状态的仓库,所有的 state ,reduce ,跟 redux 相关的 API 等都是储存在 store 中。
import {createStore} from 'redux';
import allReducers from './allReducers';
let store = createStore(allReducers);
export default store;
第五步:处理业务逻辑
- TodoList.js 为核心组件父组件,渲染了待办事项列表和过滤器,并且提供添加待办事项的方法。
TodoList.js
import React from 'react';
import TodoItem from './component/TodoItem';
import Filter from './component/FilterItem';
import {connect} from 'react-redux';
import actions from './store/actions';
class TodoList extends React.Component {
constructor(props) {
super(props);
this.status =[
{label:"所有",flag:"all"},
{label:"已完成",flag:"completed"},
{label:"未完成",flag:"uncompleted"},
]
}
add(){
var value = this.refs.input.value;
const {addTodo} = this.props;
addTodo(value);
}
render() {
const {todos} = this.props;
return <div>
<input type="text" ref="input"/><button onClick={()=>this.add()}>添加任务</button>
{todos.map((item,index)=>{
return <TodoItem
item={item}
key={index}
index={index}
/>
})}
<div className="list-mt-20">
{this.status.map((item,index)=>{
return <Filter
item={item}
key={index}
/>
})}
</div>
</div>
}
}
const mapStateToProps = (state)=>{
return{
todos:state.todos
};
};
const mapDispatchToProps = (dispatch)=>{
return {
addTodo:(val)=>dispatch(actions.addTodo(val))
}
};
export default connect(mapStateToProps,mapDispatchToProps)(TodoList);
- TodoItem.js 为任务项组件,渲染单条任务项视图,提供修改待办事项状态及删除任务的方法。
TodoItem.js
import React from 'react';
import '../index.css';
import {connect} from 'react-redux';
import actions from '../store/actions';
class TodoItem extends React.Component {
constructor(props) {
super(props);
}
del(index){
const {delTodo} = this.props;
delTodo(index);
}
changeStatus(item){
const {changeStatus} = this.props;
changeStatus(item);
}
render() {
const {item,index,filter} = this.props;
return(
<div>{filter == 'all'?<div><span className={item && item.done?'list-line':''} onClick={() => this.changeStatus(item)}>{item.text}</span>
<button onClick={() => this.del(index)}>删除</button>
</div>:(filter == item.done?<div><span className={item && item.done?'list-line':''} onClick={() => this.changeStatus(index)}>{item.text}</span>
<button onClick={() => this.del(index)}>删除</button>
</div>:null)}
</div>
)
}
}
const mapStateToProps = (state)=>{
return{
filter:state.filter,
todos:state.todos,
};
};
const mapDispatchToProps = (dispatch)=>{
return {
delTodo:(index)=>dispatch(actions.delTodo(index)),
changeStatus:(item)=>dispatch(actions.changeStatus(item)),
}
};
export default connect(mapStateToProps,mapDispatchToProps)(TodoItem);
- FilterItem.js 为过滤器组件,渲染过滤项视图。提供筛选待办事项的方法。
FilterItem.js
import React from 'react';
import '../index.css';
import {connect} from 'react-redux';
import actions from '../store/actions';
class Filter extends React.Component {
constructor(props) {
super(props);
}
filter(flag){
const {onFilter} = this.props;
if(onFilter){
onFilter(flag);
}
}
render() {
const {item} = this.props;
return<span className="filter-mr-20" onClick={()=>this.filter(item.flag)}>{item.label}</span>
}
}
const mapStateToProps = (state)=>{
return{
filter:state.filter,
};
};
const mapDispatchToProps = (dispatch)=>{
return {
onFilter:(flag)=>dispatch(actions.onFilter(flag))
}
};
export default connect(mapStateToProps,mapDispatchToProps)(Filter);
第六步:注意事项
项目中所用到的 connect 方法来自于 Redux 库。该方法是一个高阶组件,接收当前业务逻辑需要用到的 state 和 props 作为第一阶参数,接收当前业务组件作为第二阶参数。处理之后的结果是将所有的 state 和 props 作为 props 注入到当前业务组件中。