You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Grid组件fetch数据后不重渲染、提前渲染的解决方案咨询

问题根因
  • Reducer是纯函数,不允许包含异步/副作用逻辑:你在read action中调用异步的getRiders,dispatch执行时异步请求还未完成,直接返回了原始state,导致reducer状态没有触发更新
  • 状态更新时机错误:Grid组件中dispatch后立刻读取localStorage,此时异步请求未结束,localStorage还未写入最新数据,setRiders拿到的是旧值/空值;后续异步完成写入localStorage后,React默认不监听localStorage的变化,自然不会触发重渲染
  • 冗余状态定义:同时使用useReducer和useState存骑手数据,完全没有必要,useReducer返回的state本身就是响应式状态,可直接用于渲染
能不能用useContext解决?

useContext的作用是跨组件层级传递状态,解决的是状态共享的问题,不是异步更新、状态响应式的问题。你当前的问题核心是状态更新逻辑错误,哪怕把状态放到Context里也无法解决根因;如果后续需要多组件共享骑手状态,可以在修正状态逻辑的前提下,结合useContext做状态分发。

最优解决方案

核心思路是把异步逻辑从reducer中抽离,依赖React自身的响应式状态触发重渲染,localStorage仅作为持久化备份使用。

1. 修正ridersReducer,保持纯函数特性

import { updateRiders } from "../helpers/updateRiders";

export const ridersReducer = (state, action) => {
  switch (action.type){
    case 'read':
      // 直接接收异步请求返回的新数据,返回新状态
      return action.payload;
    case 'update':
      // 同步更新逻辑写在这里,接收payload返回新状态
      return updateRiders(state, action.payload);
    default:
      return state;
  }
};

2. 修正Grid组件逻辑,移除冗余状态,异步逻辑放在useEffect中

import { useEffect, useReducer, useState } from "react"
import { ridersReducer } from "../hooks/ridersReducer";
import { GridRow } from "./GridRow";
import { getRiders } from "../helpers/getRiders";

export const Grid = ({ pressed, setPressed }) => {
  const [riders, dispatch] = useReducer(ridersReducer, []);
  // 可选:增加加载状态提升用户体验
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const fetchRiders = async () => {
      setLoading(true);
      localStorage.clear();
      try {
        const data = await getRiders();
        // 处理数据逻辑
        let newRiders;
        const localRiders = JSON.parse(localStorage.getItem('riders'));
        if (localRiders === null) {
          newRiders = data.record;
        } else {
          newRiders = [...localRiders, data.record];
        }
        // 更新React状态,自动触发重渲染
        dispatch({type: 'read', payload: newRiders});
        // 持久化到localStorage
        localStorage.setItem('riders', JSON.stringify(newRiders));
      } catch (err) {
        console.error('加载骑手数据失败', err);
      } finally {
        setLoading(false);
      }
    };
    fetchRiders();
  }, [pressed]);

  if (loading) return <div>加载中...</div>;

  return (
    <table className="table table-hover">
      <thead>
        <tr>
          <th scope="col">Horas</th>
          <th scope="col">Free Riders</th>
          <th scope="col">Estado</th>
          <th scope="col">Reservar</th>
        </tr>
      </thead>
      <tbody>
        {riders?.length > 0 && Object.keys(riders).map(rider => (
          <GridRow 
            id={riders[rider].id}
            key={riders[rider].id}
            hora={riders[rider].Hora}
            riders={riders[rider].Riders}
            pressed={pressed}
            setPressed={setPressed}
            dispatch={dispatch}
          />
        ))}
      </tbody>
    </table>
  )
}

可选优化

如果需要实现多标签页之间的骑手数据同步,可以在组件中添加storage事件监听:

useEffect(() => {
  const handleStorageChange = (e) => {
    if (e.key === 'riders') {
      dispatch({type: 'read', payload: JSON.parse(e.newValue)});
    }
  };
  window.addEventListener('storage', handleStorageChange);
  return () => window.removeEventListener('storage', handleStorageChange);
}, []);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 14:15:01