Redux 之 react 结合 redux 实战篇
以 TODO
为例分析,实际开发中并不是那么简单,下面的原型只是开发中的一个原型,这个简单的例子,有助于掌握数据处理传递的原则。
一、定义 constants
这一步不是必须的
/**
* 常量统一保存,便于管理
*/
export const ADD_TODO = 'ADD_TODO';
export const TOGGLE_TODO = 'TOGGLE_TODO';
export const SET_VISIBILITY = 'SET_VISIBILITY';
//controll todo wheher show or hide
export const SHOW_ALL = 'SHOW_ALL';
export const SHOW_ACTIVE = 'SHOW_ACTIVE';
export const SHOW_COMPLETED = 'SHOW_COMPLETED';
二、定义 actionCreator
/**
* 定义 action creator
*/
import * as actionType from '../constant/index';
let nextTodo = 0;
export const addTodo = (text)=>({
type:actionType.ADD_TODO,
id:nextTodo++,
text
})
export const toggleTodo = (id)=>({
type:actionType.TOGGLE_TODO,
id
})
export const setVisibilityFilter = (filter)=>{
return {
type:actionType.SET_VISIBILITY,
filter
}
}
三、定义 reducer
拆分 reducer
SetVisibility.js
/**
* 处理 TODO 可见与不可见的 reducer
*/
import * as actionType from '../constant/index';
// 初始状态是自己设置的 后面的状态会转化
// 接收当前状态(设置默认的过滤 SHOW_ALL,如设置某些选项卡的 active 一样),和 action 返回新的 state
export const visibilityFilter = (state='SHOW_ALL',action)=>{
switch(action.type) {
case actionType.SET_VISIBILITY:
return action.filter;
default:
return state;
}
}
addTodo.js
/**
* 定义处理 action 的 reducers
*/
import * as actionType from '../constant/index';
//传入当前的状态空数、action
export const todos = (state = [],action)=>{
switch(action.type){ // 匹配用户触发的 actionType
case actionType.ADD_TODO:
// 合并上一次的状态和当前的状态 返回 todos 数组
return [
...state,//把数组展开合并
{
id:action.id,
text:action.text,
completed:false//用户控制 TODO 是否处于点击完成的状态 默认 false 没点击
}
]
// TODO 列表来回切换 遍历 add_todo 返回的数组 通过 completed 来判断
case actionType.TOGGLE_TODO:
return state.map(todo=>(todo.id===action.id)?{...todo,completed:!todo.completed}:todo)
default:
return state;//匹配不到返回 state
}
}
合并 reducer
/**
* 合并 reducers
*/
import { combineReducers } from 'redux'
import {todos} from './addTodo';
import {visibilityFilter} from './SetVisibility';
export default combineReducers({
todos, //这些键其实就是被拆分的状态,后面在容器组件中需要通过 connect 链接
visibilityFilter
});
四、定义 store
import { applyMiddleware, createStore } from 'redux';
import reducer from '../reducers/index';
import logger from 'redux-logger';
// 创建 store 用来存储状态
export const store = createStore(
reducer,
applyMiddleware(logger) //处理日志中间件
)
五、结合 react-redux
这里忽略展示组件,完成源码看文章结尾
- 首先我们在
container
组件中处理好之前分解合并的那些reducer
的键,然后在通过connect
链接,传递给展示组件的属性使用
容器组件处理
react-todos/src/container/FilterLink.js
// 处理数组过滤
import { connect } from 'react-redux';
import Link from '../components/Link';
import { setVisibilityFilter } from '../actions/index';
// 这里的 ownProps 指的是 FilterLink
// 这里的 state 其实就是之前分解的 todos,visibilityFilter
const mapStateToProps = (state, ownProps) => {
return {
active:ownProps.filter === state.visibilityFilter
}
}
/**
如果 mapDispatchToProps 是一个函数,会得到 dispatch 和 ownProps(容器组件的 props 对象)两个参数。
*/
const mapDispatchToProps = (dispatch, ownProps) => ({
// 这里处理对应的事件,传递给展示组件的属性
onClick: () => {
dispatch(setVisibilityFilter(ownProps.filter))
}
})
export default connect(
mapStateToProps,
mapDispatchToProps
)(Link);
- 分析
- 这里通过
connect
组件把之前reducer
处理的那些状态链接
- 这里通过
export default combineReducers({
todos, //这些键其实就是被拆分的状态,后面在容器组件中需要通过 connect 链接
visibilityFilter
});
react-todos/src/container/VisibilityTodoList.js
/**
* 处理可见于不可见组件的逻辑
*/
import {connect} from 'react-redux';
import TodoList from '../components/TodoList';
import {toggleTodo} from '../actions/index';
import * as actionType from '../constant/index';
console.log(toggleTodo)
// todos 是返回的数组,filter 是过滤的选项如 SHOW_ALL SHOW_ACTIVE.
const getVisibilityTodos = (todos,filter)=>{
switch(filter) {
case actionType.SHOW_ALL:
return todos;
case actionType.SHOW_ACTIVE:
return todos.filter(t => !t.completed);
case actionType.SHOW_COMPLETED:
return todos.filter(t => t.completed);
default:
throw new Error('未知的'+filter);
}
}
// 把状态转化为展示组件的属性转递过去
/**
*
* @param {*} state 也就是
* export default CombineReducers({
Todos,
SetVisibility
*});
* @param {*} ownProps 返回的容器组件本身的参数 如<Filter name="poetries">此时的 ownProps 就是 name 了
*/
const mapStateToProps = (state) => {
return {
todos: getVisibilityTodos(state.todos,state.visibilityFilter),
count:state.todos.length
}
}
/**
* 如果 mapDispatchToProps 是一个对象,它的每个键名也是对应 UI 组件的同名参数,键值应该是一个函数,会被当作 Action creator ,返回的 Action 会由 Redux 自动发出
*/
const mapDispatchToProps = {
onTodoClick: toggleTodo
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
react-todos/src/container/addTodos.js
/**
* Addtodo 的处逻辑
*/
import React, { Component } from 'react';
import {addTodo} from '../actions/index';
import AddTask from '../components/addTodo';
import {connect} from 'react-redux';
const mapStateToProps = (state, ownProps) => ({
})
const mapDispatchToProps = {
addTodo:addTodo
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(AddTask);
到此分析完毕,展示组件就不分析了,展示组件本身是没有数据的,需要 container 处理传递
完整的源码
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论