You need to enable JavaScript to run this app. ReactJS中useReducer如何接收props传入的异步数据作为初始状态
优惠活动
大模型
产品
解决方案
定价
更多

ReactJS中useReducer如何接收props传入的异步数据作为初始状态

问题根因
  • useReducer 传入的初始状态参数 仅在组件首次挂载阶段计算一次,后续props更新不会自动重新计算初始值,也不会自动同步到reducer维护的内部状态中。
  • 你当前的执行流存在时序错位:
    1. 组件首次挂载时,父组件的axios异步请求尚未返回,传入的products为父组件useState([])定义的初始空数组,因此reducer初始化拿到的data为空值。
    2. 异步请求完成后,父组件更新productList状态并向TableSorter传入新的products数据,此时组件已经完成首次挂载,reducer的初始状态不会重新执行赋值逻辑,因此内部data始终为空。
    3. 目前Table.Body直接遍历props传入的products虽然能渲染内容,但完全绕开了reducer维护的排序逻辑,排序功能完全无法生效。
修复步骤

1. 扩展reducer的action分支

为reducer新增处理外部数据同步的逻辑,用来接收从props传入的最新产品数据:

function exampleReducer(state, action) {
  switch (action.type) {
    // 新增的同步外部数据分支
    case 'SET_EXTERNAL_DATA':
      return {
        column: null,
        data: action.payload,
        direction: null,
      }
    case 'CHANGE_SORT':
      // 原有排序逻辑保持不变
      if (state.column === action.column) {
        return {
          ...state,
          data: state.data.slice().reverse(),
          direction:
            state.direction === 'ascending' ? 'descending' : 'ascending',
        }
      }
      return {
        column: action.column,
        data: _.sortBy(state.data, [action.column]),
        direction: 'ascending',
      }
    default:
      throw new Error()
  }
}

2. 移除reducer初始状态对props的直接依赖

将useReducer的初始状态改为独立的空结构,不再依赖传入的products做初始化:

function TableSorter({products}) {
  // 初始状态固定为空结构,避免和props绑定
  const initialState = {
    column: null,
    data: [],
    direction: null,
  }
  const [state, dispatch] = useReducer(exampleReducer, initialState)
  const { column, data, direction } = state

3. 通过副作用监听props变化,同步到reducer状态

使用useEffect监听传入的products值变化,当检测到数据更新时,派发对应action把最新数据同步到reducer的内部状态:

// 监听products变化,自动同步到reducer内部
useEffect(() => {
  // 仅当外部products和内部data引用不一致时才更新,避免死循环
  if (products !== state.data) {
    dispatch({
      type: 'SET_EXTERNAL_DATA',
      payload: products
    })
  }
}, [products, state.data])

4. 替换表格渲染的数据源

将Table.Body里直接遍历props的逻辑,改为遍历reducer维护的state.data,让所有排序操作的结果直接作用在渲染的数据源上:

<Table.Body>
  {data?.map(({name, expiration_date, sku, category, price, shipment_batch}) => (
    <Table.Row key={name}>
      <Table.Cell>{name}</Table.Cell>
      <Table.Cell>{expiration_date}</Table.Cell>
      <Table.Cell>{sku}</Table.Cell>
      <Table.Cell>{category}</Table.Cell>
      <Table.Cell>{price}</Table.Cell>
      <Table.Cell>{shipment_batch}</Table.Cell>
    </Table.Row>
  ))}
</Table.Body>

补充说明:SET_EXTERNAL_DATA分支里重置了排序相关的column和direction值,是为了当外部传入全新的数据集(比如用户重新搜索拿到的产品列表)时,自动清空之前残留的排序状态,符合通用表格组件的交互预期。

内容的提问来源于stack exchange,提问作者c0caDJ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.03 18:06:04