react|react3-Redux

Redux

  1. 状态管理器
  2. 集中式管理应用中的状态数据,以一种可预测的方式更新状态数据
  3. react-redux 绑定库官网
    redux 与 react 没有任何直接关系,所以在 react 中要使用 redux 进行状态管理,通常还需要额外的绑定库:react-redux
概念
  1. store:仓库,是一个容器,主要用于集中管理应用中的状态
  2. state:状态,是各组件需要共享的状态数据
  3. action:是一个普通对象,通常用于描述发生了什么。这个对象中一般有两个属性:type 和 payload
  4. action creator:action 创建函数,是一个函数结构,主要用于创建 action 对象,以实现 action 的复用
  5. reducer:是用于同步更新状态数据的纯函数。该函数以 state 和 action 作为参数,返回新的 state 状态数据。函数签名是:(state, action) => newState
    注:纯函数 返回值依赖于参数 函数主体内部不产生任何副作用

  6. 【react|react3-Redux】Reducer 必需符合以下规则:
  • 仅使用 state 和 action 参数计算新的状态值
  • 禁止直接修改 state。必须通过复制现有的 state 并对复制的值进行更改的方式来做 不可变更新(immutable updates)
  • 可使用lodash来实现深拷贝
  • 禁止任何异步逻辑、依赖随机值或导致其他“副作用”的代码
  1. reducer 函数内部的逻辑通常遵循以下步骤:
  • 检查 reducer 是否关心这个 action
  • 如果是,则复制 state,使用新值更新 state 副本,然后返回新 state,否则,返回原来的 state 不变
  • dispatch:是一个函数,传递 action 作为参数,以调用到 reducer 进行状态更新(在组件中不能直接调用 reducer() 进行状态更新,注reducer() 函数的调用是封装在 dispatch() 函数体内部实现的。)
  • selector:是一个函数,用于从 store 的 state 状态树中提取片段。
三大原则 单一数据源 整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中
State 是只读的 唯一改变 state 的方法就是触发 action(即调用 dispatch(action) 方法),action 是一个用于描述已发生事件的普通对象
使用纯函数来执行修改 为了描述 action 如何改变 state tree ,你需要编写 reducers
使用
  1. 安装
  • $ npm i redux@4.1.2 react-redux@7.2.6
  • $ yarn add redux@4.1.2 react-redux@7.2.6
  1. 创建 reducer
  • 创建.src/actions/ constants.js目录
/** action type 的取值 */ export const ADD_TO_CART = Symbol('add_to_cart')

  • 创建 action creator
    创建 ./src/actions/cart.js 目录,定义 action creator(action创建函数),如:
/** * 定义 action creator (action创建函数),用于创建 action 对象,以便于复用 action 对象 */import { ADD_TO_CART } from "./constants"/** * 用于创建添加到购物车时使用的 action 对象 */ export const addToCartAction = (product) => { return { type: ADD_TO_CART, payload: product, } }

  • 创建 ./src/reducers/cart.js 目录,定义 reducer 函数,如:
/** * 实现购物车状态数据管理 */import _ from 'lodash' import { ADD_TO_CART, REMOVE_FROM_CART } from "../actions/constants"/** * 初始状态数据 */ const initialState = { cart: [], }/** * reducer 函数,是一个纯函数,用于同步更新状态数据 * @param {*} state 旧状态数据 * @param {*} action action对象,有 type 和 payload 属性 * @returns 返回新的状态数据 */ const cartReducer = (state = initialState, { type, payload }) => {/** 对 state 进行深克隆 */ const copyState = _.cloneDeep(state)/** * 使用 switch 多分支选择,来判断当前 action 的动作类型 */ switch (type) { case ADD_TO_CART: // 添加购物车 copyState.cart.push(payload) return copyState case REMOVE_FROM_CART: // 从购物车中删除商品 copyState.cart = copyState.cart.filter(prod => prod.id !== payload.id) return copyState default: return state } }export default cartReducer

  • ./src/reducers/index.js将各独立的 reducer 合并为根 reducer,如:
/** * 将多个独立的 reducer 合并为一个根 reducer */import { combineReducers } from 'redux' import cartReducer from './cart'const rootReducer = combineReducers({ shoppingCart: cartReducer, })export default rootReducer

  • 创建 Store
    创建 ./src/store 目录,定义 Store:
/** * 创建 Store 仓库 */import { createStore } from 'redux' import rootReducer from '../reducers'/** * 基于根 reducer 来创建 store */ const store = createStore(rootReducer)export default store

  • 入口文件.src/index.js组件中连接 Redux 的 Store
import React from 'react' import ReactDOM from 'react-dom' import App from './App' import {Provider} from "react-redux"; import store from "./store"; ReactDOM.render( , document.getElementById('root') )

  • 文件中使用
import React from 'react' import {useDispatch, useSelector} from "react-redux"; // 引入并结构出useDispatch(使用方法,改变数据)useSelector(拿到数据) impot {addToCartActio} fron "../actions/cart.js"function React() { const dispatch=useDispatch() const cart=useSelector(state=>state.shoppingCart.cart) // 格式一个回调函数,state.空间名字.仓库数据名字 const clickHandler=()=>{ dispatch(addToCartAction({id:0,title:'商品信息'})) // 触发的actions事件 } return (
react
) } export default React

异步任务
  1. 处理异步任务需要三方包
  • yarn add redux-thunk
  1. 在store中引入
import {createStore,applyMiddleware} from "redux"; import logger from 'redux-logger' // 记录仓库状态数据 import thunk from 'redux-thunk' // 异步仓库任务处理 import rootReducer from "../reducers/index"const store = createStore(rootReducer,applyMiddleware(logger,thunk)) export default store

  1. 在需要异步处理的任务中写法,如actions中登录网络请求
import {LOGIN_SUCCESS,LOGIN_FAILED,LOGIN_RESET} from '../constants/action-types' import {postLogin} from '../api/user'export const loginSuccessAction=info=>{ return { type:LOGIN_SUCCESS, payload:info, } } // 重置 export const loginResetAction=()=>{ return{ type: LOGIN_RESET, } } // 异步请求登录网络 export const loginAsyncAction=(info)=>{ /** * 返回的这个函数,会自动被 redux-thunk 中间件调用执行。 * 在调用执行这个函数时,会自动传递 dispatch 作为参数。 * 不要求返回的这个函数保持纯净(即可以包含异步逻辑) */ return async dispatch=>{ const {status,data}=await postLogin(info) if(status===200){ // 登录成功 dispatch(loginSuccessAction(data)) return true }else { // 登录失败 dispatch({ type:LOGIN_FAILED }) return false } }}

    推荐阅读