react3-Redux

     阅读:46

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. 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(
 <Provider store={store}>
         <App/>
 </Provider>,
  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 (
    <div onClick={clickHandler}>react</div>
  )
}
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
        }
    }

}