📢 React状态管理新姿势:useReducer与纯函数的完美协奏曲

88 阅读4分钟

今天咱们来聊聊React中的状态管理,这就像管理一家公司——小公司靠老板吼(useState),大公司靠制度管(useReducer)!先看看组件间通信的几种方式:

🧩 组件通信的"职场关系学"

  1. 父子组件:像老板给员工派任务,通过props下发指令
<Child task={missionImpossible} />

2. 子父组件:员工提交报告,通过自定义事件回调

const Child = ({ onSubmit }) => (
  <button onClick={() => submit('KPI达标!')}>汇报</button>
)

3. 兄弟组件:需要经过"老父亲"中转,像两个熊孩子传纸条被班主任截获

<Parent>
  <BrotherA onMessage={setMsg} />
  <BrotherB msg={msg} />
</Parent>

4. 跨层级通信:当公司规模扩大,需要建立集团制度

*   普通方案:`useContext` + `createContext` → 部门墙太厚,文件传递效率低
*   终极方案:`useReducer` → 建立全集团标准化流程

🧐 为什么需要useReducer?

想象你管理一家跨国企业(大型应用),如果每个部门(组件)都:

// 混乱的状态管理现场
<LoginContext.Provider>
  <ThemeContext.Provider>
    <TodosContext.Provider>
      <Layout>...</Layout>
    </TodosContext.Provider>
  </ThemeContext.Provider>
</LoginContext.Provider>

这种"俄罗斯套娃式"管理会导致:

  • 🤯 嵌套地狱(Prop Drilling)
  • 🔄 状态更新难以追踪
  • 🎲 数据流像没舵的船——随时翻

这样虽然可以实现我们的跨层级数据通信,但是代码的可读性实在太差,在大型项目中,我们需要的数据太多,这种方式不可取

🦸 useReducer登场:公司的标准化制度

它由三部分组成:

  1. initialState - 公司章程
  2. reducer - 法务部(纯函数)
  3. dispatch - 内部办公系统
// 1. 定义公司章程(初始状态)
const initialState = { count: 0 }

// 2. 建立法务部(reducer纯函数)
const reducer = (state, action) => {
  switch (action.type) {
    case '涨工资': 
      return { count: state.count + 1 }
    case '扣绩效': 
      return { count: state.count - 1 }
    default:
      return state
  }
}

// 3. 启用办公系统
const [state, dispatch] = useReducer(reducer, initialState)

// 财务部发起流程(组件内触发)
<button onClick={() => dispatch({ type: '涨工资' })}>
  申请加薪
</button>

⚖️ 为什么reducer必须是"纯函数"?

纯函数 相同地的输入,一定会有相同的输出,没有副作用,不操作外部变量、不发送请求、不改DOM,管理数据状态 纯函数去管理, 全局状态更正确

看个反面教材——不守规矩的会计:

let total = 0 // 公司小金库
function addToTotal(a) {
  total += a // 偷偷改外部变量(查账会出问题!)
  return total
}

而优秀的法务部(纯函数):

// 相同输入永远得到相同输出
function add(a, b) {
  return a + b // 光明正大算账
}

纯函数的三大纪律

  1. 不操作外部变量(不碰小金库)
  2. 不发送请求(不私自联系客户)
  3. 不改DOM(不擅自装修办公室)

🚀 useReducer实战:双计数器管理系统

假设公司有两个部门需要独立核算:

// 初始化集团财务
const initialState = {
  count1: 0, // 研发部资金池
  count2: 10 // 市场部资金池
}

// 集团审计制度(reducer)
function reducer(state, action) {
  switch (action.type) {
    case '研发部加薪':
      return { ...state, count1: state.count1 + 1 }
    case '市场部加薪':
      return { ...state, count2: state.count2 + 1 }
    case '全员调薪':
      return {
        count1: state.count1=action.payload,
        count2: state.conut2=action.payload
      }
    // ...其他财务流程
  }
}

function CFO() { // 财务总监组件
  const [state, dispatch] = useReducer(reducer, initialState)
  const [input, setInput] = useState(0)

  return (
    <>
      <div>
        <h3>研发部资金: {state.count1}</h3>
        <button onClick={() => dispatch({ type: '研发部加薪' })}>
          申请研发部调薪
        </button>
      </div>
      
      <div>
        <h3>市场部资金: {state.count2}</h3>
        <button onClick={() => dispatch({ type: '市场部加薪' })}>
          申请市场部调薪
        </button>
      </div>
      
      <input 
        value={count} 
        onChange={e => setConut(e.target.value)} 
        placeholder="输入全员薪资标准"
      />
      <button onClick={() => dispatch({ 
        type: '全员调薪', 
        payload: parseInt(count) 
      })}>
        执行全员调薪
      </button>
    </>
  )
}

13.gif

🔍 执行流程解析(以调薪为例):

  1. 财务输入调薪数额:setCount(10000)

  2. 点击按钮发起申请:dispatch({ type: '全员调薪', payload: 10000 })

  3. 法务部(reducer)处理申请:

    case '全员调薪':
      return {
        count1: action.payload, // 研发部调薪
        count2: action.payload // 市场部调薪
      }
    
  4. 生成新状态触发重新渲染

  5. 两个部门的资金显示同时更新

🆚 useState vs useReducer 抉择指南

场景useState(小卖部)useReducer(沃尔玛)
状态类型独立简单值关联复杂对象
更新逻辑直接set通过action派发
数据流追踪较困难清晰可追踪
跨组件更新需配合context天然适合
可维护性小型项目友好中大型项目必备

💡 最佳实践心得

  1. 像立法一样设计action

    // 反例 - 含糊不清
    dispatch({ type: '改数字', value: 10 })
    
    // 正例 - 语义明确
    dispatch({ type: '设置研发预算', payload: 1000000 })
    
  2. 永远返回新对象

    // 错误!直接修改原状态(相当于做假账)
    state.count = 100 
    return state
    
    // 正确!返回全新状态对象
    return { ...state, count: 100 } 
    

count: 100 是你修改的具体某个状态会覆盖...state中原始的

  1. 拆分大reducer

    // 当制度太复杂时(超过200行)
    const rootReducer = combineReducers({
      finance: financeReducer, // 财务制度
      hr: hrReducer // 人事制度
    })
    

🌟 总结

用useReducer管理状态就像建立现代企业制度:

  • dispatch 是OA办公系统(流程可控)
  • reducer 是法务部(确保合规)
  • action 是标准化表单(减少沟通成本)

下次当你的组件树开始变成"俄罗斯套娃",当useState的回调函数蔓延成"面条代码",请记得召唤useReducer这位管理大师!毕竟——好的程序员不写代码,他们设计制度。🫡

今日金句:用useState是手工作坊,用useReducer是工业化生产,而用Redux...那是建立跨国集团!

image.png