React hooks - useReducer

useReducer

用法
  1. 可同时更新多个状态,且能把对状态的修改从组件中独立出来,状态更新逻辑较复杂时可以考虑使用。
  2. 代码逻辑更清晰,代码行为易预测:组件负责发出行为,useReducer 负责更新状态
javascript 复制代码
const [state, dispatch] = useReducer(reducer, initState, initAction?)
  1. reducer=(prevState, action)=> { return '处理好的新状态' } 状态处理函数,接收上一次的旧值,以及dispatch穿入的信息对象,进行一系列处理,返回处理好的新状态(一定要是个崭新的对象,为了组件能够监听到状态的变化)
  2. initState 初始状态
  3. initAction 预处理函数,可选,将初始状态传入进行预处理,返回值被当做初始状态
  4. state 获取状态值
  5. dispatch({type: '此次操作的类型', payload: '提交此次操作需要用到的数据' }) 修改状态值,接收一个信息对象,触发reducer函数的执行,更新 state状态,状态更新导致组件重新渲染
使用
javascript 复制代码
import React from 'react'

// 定义默认值的类型,从默认值身上获取
type UserType = typeof defaultState
// 初始数据
const defaultState = { name: 'liulongbin', age: 16 }
// 状态处理函数
const reducer = (prevState: UserType) => {
  console.log('触发了 reducer 函数')
  return prevState
}
// 预处理函数
const initAction = (initAction: UserType) => {
  return {...initAction , age:Math.round(Manth.abs(initState.age))||18}
}

父组件

javascript 复制代码
export const Father: React.FC = () => {
  const [state, dispatch] = useReducer(reducer, defaultState,initAction)
  return (
    <div>
      <button>修改 name 的值</button>
      <div className="father">
        <Son1 />
        <Son2 />
      </div>
    </div>
  )
}

子组件1

javascript 复制代码
const Son1: React.FC<UserType & {dispatch : React.Dispatch<ActionType>}> = (props) => {
  const {dispatch, ...user} = props
  const changeAge = () => {
    dispatch({type: 'AGE_INCREMENT', payload: 2}) // 年龄一次自增2
  }
  return (
    <div className="son1">
      {JSON.stringify(user)}
      <button onClick={()=>changeAge}>年龄自增2</button>
    </div>
  )
}

子组件2

javascript 复制代码
const Son2: React.FC<UserType & {dispatch : React.Dispatch<ActionType>}> = (props) => {
  const {dispatch, ...user} = props
  const changeAge = () => {
    dispatch({type: 'AGE_DECREMENT', payload: 1}) // 年龄一次自减1
  }
  return (
    <div className="son2">
      {JSON.stringify(user)}
      <button onClick={()=>changeAge}>年龄自减1</button>
      {/* 传第二手dispatch */}
      <GrandSon dispatch={ dispatch } /> 
    </div>
  )
}

孙子组件

javascript 复制代码
const GrandSon: React.FC<{dispatch : React.Dispatch<ActionType>}> = (props) => {
  const { dispatch } = props
  const reset = () => {
    dispatch({type: 'RESET'}) 
  }
  return (
    <div className="grand-son">
      <button onClick={()=>reset}>重置</button>
    </div>
  )
}

样式

css 复制代码
.father {
  display: flex;
  justify-content: space-between;
  width: 100vw;
}

.son1 {
  background-color: orange;
  min-height: 300px;
  flex: 1;
  padding: 10px;
}

.son2 {
  background-color: lightblue;
  min-height: 300px;
  flex: 1;
  padding: 10px;
}
使用 Immer 更简单的编写 reducer

从 use-immer 中导入 useImmerReducer 函数,并替换掉 React 官方的 useReducer 函数的调用

javascript 复制代码
npm install immer use-immer -S

修改 reducer 函数中的业务逻辑,case 代码块中不需要 return 新对象了,可在 prevState 上进行修改

因为 Immer 内部会复制并返回新对象

javascript 复制代码
// 状态处理函数
const reducer = (prevState: UserType, action: ActionType) => {
  console.log('触发了 reducer 函数', action)
  switch (action.type) {
    // 修改名字
    case 'UPDATE_NAME':
      prevState.name = action.payload
      break
    // 年龄自增payload
    case 'INCREMENT':
      prevState.age += action.payload
      break
    // 年龄自减payload
    case 'DECREMENT':
      prevState.age -= action.payload
      break
    // 重置
    case 'RESET':
      return initAction(defaultState)
    default:
      return prevState
  } 
}
javascript 复制代码
export const Father: React.FC = () => {
  // 把 useReducer() 的调用替换成 useImmerReducer()
  const [state, dispatch] = useImmerReducer(reducer, defaultState,initAction)
}
注意事项
  1. 状态被useReducer接管后,不能直接修改 state 的值,因为存储在 useReducer 中的数据都是"不可变"的,要想修改 useReducer 中的数据,必须使用 dispatch 函数 触发 reducer 函数的重新计算。
相关推荐
screct_demo3 小时前
詳細講一下在RN(ReactNative)中,6個比較常用的組件以及詳細的用法
javascript·react native·react.js
光头程序员11 小时前
grid 布局react组件可以循数据自定义渲染某个数据 ,或插入某些数据在某个索引下
javascript·react.js·ecmascript
limit for me11 小时前
react上增加错误边界 当存在错误时 不会显示白屏
前端·react.js·前端框架
浏览器爱好者11 小时前
如何构建一个简单的React应用?
前端·react.js·前端框架
VillanelleS14 小时前
React进阶之高阶组件HOC、react hooks、自定义hooks
前端·react.js·前端框架
傻小胖15 小时前
React 中hooks之useInsertionEffect用法总结
前端·javascript·react.js
flying robot1 天前
React的响应式
前端·javascript·react.js
GISer_Jing1 天前
React+AntDesign实现类似Chatgpt交互界面
前端·javascript·react.js·前端框架
智界工具库2 天前
【探索前端技术之 React Three.js—— 简单的人脸动捕与 3D 模型表情同步应用】
前端·javascript·react.js
我是前端小学生2 天前
我们应该在什么场景下使用 useMemo 和 useCallback ?
react.js