盒子
盒子
文章目录󰁋
  1. 一、定义constants
  2. 二、定义actionCreator
  3. 三、定义reducer
  4. 四、定义store
  5. 五、结合react-redux

Redux之react结合redux实战篇(十)

TODO为例分析,实际开发中并不是那么简单,下面的原型只是开发中的一个原型,这个简单的例子,有助于掌握数据处理传递的原则。

一、定义constants

这一步不是必须的

1
2
3
4
5
6
7
8
9
10
11
/**
* 常量统一保存,便于管理
*/
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

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
/**
* 定义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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 处理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
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
/**
* 定义处理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

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 合并reducers
*/

import { combineReducers } from 'redux'
import {todos} from './addTodo';
import {visibilityFilter} from './SetVisibility';

export default combineReducers({
todos, //这些键其实就是被拆分的状态,后面在容器组件中需要通过connect链接
visibilityFilter
});

四、定义store

1
2
3
4
5
6
7
8
9
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

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
// 处理数组过滤

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处理的那些状态链接
1
2
3
4
5

export default combineReducers({
todos, //这些键其实就是被拆分的状态,后面在容器组件中需要通过connect链接
visibilityFilter
});

react-todos/src/container/VisibilityTodoList.js

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
47
48
49
50
51
52
/**
* 处理可见于不可见组件的逻辑
*/
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 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处理传递

完整的源码

https://github.com/poetries/react-todos

支持一下
扫一扫,支持poetries