Redux:Reducers

action只是描述了“发生了什么事情(导致state需要更新)”,但并不直接参与更新state的操作。state的更新由reducer函数执行。

其基本模式是:(state,action)=> newState

设计组件state的结构:

    在开始敲代码之前,我们要先设计好组件state的结构。我们得先明确state需要哪些变量,哪些是纯粹的数据,哪些和UI有关。用合适的结构组织起来(data类的state和UI类的state最好相互独立)。

In a more complex app, you‘re going to want different entities to reference each other. We suggest that you keep your state as normalized as possible, without any nesting. Keep every entity in an object stored with an ID as a key, and use IDs to reference it from other entities, or lists. Think of the app‘s state as a database.

如何处理action:

往reducer函数传入参数之后,根据action的type属性,函数执行对应的对state的更新。文档指出三件在reducer函数中必须避免的事情:

1.改变传入的参数。

2.执行“引发其他作用“的操作,比如调用其他api、路由跳转

3.调用”无更新无关“的函数,如Date.now()

For now, just remember that the reducer must be pure. Given the same arguments, it should calculate the next state and return it. No surprises. No side effects. No API calls. No mutations. Just a calculation.

使用

初始化state:

在第一次调用reducer的时候,传入的state回事一个undefined,此时我们可以给它进行初始化。

 1 import { VisibilityFilters } from ‘./actions‘
 2
 3 const initialState = {
 4   visibilityFilter: VisibilityFilters.SHOW_ALL,
 5   todos: []
 6 }
 7
 8 function todoApp(state, action) {
 9   if (typeof state === ‘undefined‘) {
10     return initialState
11   }
12
13   // For now, don‘t handle any actions
14   // and just return the state given to us.
15   return state
16 }

我们可以借助ES6的参数默认值简化代码:

1 function todoApp(state = initialState, action) {
2   // For now, don‘t handle any actions
3   // and just return the state given to us.
4   return state
5 }

最终的reducer可以是这样:

 1 function todoApp(state = initialState, action) {
 2   switch (action.type) {
 3     case SET_VISIBILITY_FILTER:
 4       return Object.assign({}, state, {
 5         visibilityFilter: action.filter
 6       })
 7     case ADD_TODO:
 8       return Object.assign({}, state, {
 9         todos: [
10           ...state.todos,
11           {
12             text: action.text,
13             completed: false
14           }
15         ]
16       })
17     default:
18       return state
19   }
20 }

记住几个地方:

*只要符合switch语句的某个case,返回的state是一个新的对象。

*匹配不到case的,default返回的是原先的state。任何意外的action都不触发state更新,可控才是最重要的。

*Object.assign是ES6的api,许多浏览器可能并不原生支持,开发时记得安装插件 Babel plugin。另,assign第一个参数必须是空对象;也可以用 对象扩展运算符{...state,...update}。

*switch语句不是必须的,reducer内部的结构完全由自己设计

分解(解构)reducer:

当我们的state涉及很多变量的时候,像上面那样写在同一个函数中难免会显得又长又臭。

作者给出的优化方法是,根据action的type属性,将state的更新划分为几个类型,每种类型的更新任务由对应的reducer小单元来处理。也即将app的Reducer解耦为若干个小reducer,此时Reducer只负责action类型判断和任务分配,小reducer负责返回state需要更新的属性

看下面的例子:

 1 function todos(state = [], action) {
 2   switch (action.type) {
 3     case ADD_TODO:
 4       return [
 5         ...state,
 6         {
 7           text: action.text,
 8           completed: false
 9         }
10       ]
11     case TOGGLE_TODO:
12       return state.map((todo, index) => {
13         if (index === action.index) {
14           return Object.assign({}, todo, {
15             completed: !todo.completed
16           })
17         }
18         return todo
19       })
20     default:
21       return state
22   }
23 }
24
25 function visibilityFilter(state = SHOW_ALL, action) {
26   switch (action.type) {
27     case SET_VISIBILITY_FILTER:
28       return action.filter
29     default:
30       return state
31   }
32 }
33
34 function todoApp(state = {}, action) {
35   return {
36     visibilityFilter: visibilityFilter(state.visibilityFilter, action),
37     todos: todos(state.todos, action)
38   }
39 }

这段代码结构很清晰,todos函数负责管理事件的添加和‘是否完成’的标记,visibilityFilter负责列表的显示规则,真正统筹state的是todoApp这个顶层Reducer。

要留意

小reducer单元中,参数state都有默认值,因为每个reducer分别执行不同的更新任务,因此他们得到的往往是state的一部分属性,这部分属性和该次更新的类型有关。他们返回的值是新state的一部分。

顶层Reducer才是返回新state的地方。

另外,Redux提供了一个工具 combineReducers()来帮助我们实现上面这种分解reducer功能的逻辑:

 1 import { combineReducers } from ‘redux‘
 2
 3 const todoApp = combineReducers({
 4   visibilityFilter,
 5   todos
 6 })
 7
 8 export default todoApp
 9
10 等价于
11
12 export default function todoApp(state = {}, action) {
13   return {
14     visibilityFilter: visibilityFilter(state.visibilityFilter, action),
15     todos: todos(state.todos, action)
16   }
17 }

就是一个生成Reducer的工具。

时间: 2024-08-30 11:51:34

Redux:Reducers的相关文章

[Functional Programming ADT] Combine Multiple State ADT Based Redux Reducers

Redux provides a convenient helper for combining many reducers called combineReducer, but it focuses in on specific attributes on our state, making it incompatible with using the State ADT. We would like a way to avoid keeping all of our reducers in

nextjs的开发使用(二)---引入redux状态管理

在上篇文章中,基于react的nextjs服务端渲染框架学习使用 学习了解了一些关于nextjs的东西,并做了一个小demo,这篇文章将对上篇文章做一个补充,在nextjs中引入redux 安装 // 安装redux相关依赖 yarn add redux redux-saga react-redux // 安装next.js对于redux的封装依赖包 yarn add next-redux-wrapper next-redux-saga yarn add redux react-redux 创建

react--redux状态管理

为了解决组件嵌套太深的问题状态管理的概念在前端横空出世,本文使用redux作为例子,先安装两个包"react-redux": "^7.0.2", "redux": "^4.0.1", npm install redux react-redux --save 新增pages/reduxComponent.js, 内容如下 import React, { Component } from 'react'; import { con

[Redux] Colocating Selectors with Reducers

We will learn how to encapsulate the knowledge about the state shape in the reducer files, so that the components don’t have to rely on it. In current VisibleTodoList.js: import { connect } from 'react-redux'; import { withRouter } from 'react-router

[Redux] Understand Redux Higher Order Reducers

Higher Order Reducers are simple reducer factories, that take a reducer as an argument and return a new reducer. In that new reducer, you can customize the behaviour of the original one which helps reducing the reducer logic. In this lesson, we'll se

Redux 的基础概念-API

三个基本原则 整个应用只有唯一一个可信数据源,也就是只有一个 Store State 只能通过触发 Action 来更改 State 的更改必须写成纯函数,也就是每次更改总是返回一个新的 State,在 Redux 里这种函数称为 Reducer Actions Action 很简单,就是一个单纯的包含 { type, payload } 的对象,type 是一个常量用来标示动作类型,payload 是这个动作携带的数据.Action 需要通过 store.dispatch() 方法来发送. 比

redux+flux(一:入门篇)

React是facebook推出的js框架,React 本身只涉及UI层,如果搭建大型应用,必须搭配一个前端框架.也就是说,你至少要学两样东西,才能基本满足需要:React + 前端框架. Facebook官方使用的是 Flux 框架.本文就介绍如何在 React 的基础上,使用 Flux 组织代码和安排内部逻辑. 首先,Flux将一个应用分成四个部分: Flux 的最大特点,就是数据的"单向流动". 用户访问 View View 发出用户的 Action Dispatcher 收到

redux 初步理解

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; color: #454545 } p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; color: #454545; min-height: 14.0px } span.s1 { font: 12.0px "PingFang SC" } 派发一个 action 给 reducer, r

理解Javascript的状态容器Redux

Redux要解决什么问题? 随着 JavaScript 单页应用开发日趋复杂,JavaScript 需要管理比任何时候都要多的 state (状态). 这些 state 可能包括服务器响应.缓存数据.本地生成尚未持久化到服务器的数据,也包括 UI 状态,如激活的路由,被选中的标签,是否显示加载动效或者分页器等等.管理不断变化的 state 非常困难.如果一个 model 的变化会引起另一个 model 变化,那么当 view 变化时,就可能引起对应 model 以及另一个 model 的变化,依