我最近注意到的奇怪反应行为

问题描述 投票:0回答:1

我正在开发一个 React 组件(FSRenderer),它获取和转换数据,然后渲染网格和标题。我的问题与 Redux 管理的加载状态以及渲染行为有关。

事情是这样的:

  • 当获取和转换数据时,我使用dispatch(setLoading(true))将Redux加载状态设置为true。

  • 转换完成后,我设置转换后的数据(transformedData)、转换后的配置(transformedConfig),最后使用dispatch(setLoading(false))将Redux加载状态更新为false。

  • 但是,我注意到在transformedData和transformedConfig更新之前加载状态就变成了false。

  • 因此,尽管转换随后立即完成,但网格暂时不显示任何数据时会发生额外的渲染。


const [transformedData, setTransformedData] = useState<any[]>([]);
const [transformedConfig, setTransformedConfig] = useState<Object>({});
const gridRef = useRef();

useEffect(() => {
    (async () => {
        try {
            dispatch(setLoading(true)); 

            const data = await dmServices.getGridData();

            setTransformedData(data);
            setTransformedConfig(data);


            dispatch(setLoading(false)); // This seems to execute before `setTransformedData` and `setTransformedConfig`
        } catch (err) {
            console.error('Error while fetching and transforming data:', err);
            dispatch(setLoading(false));
        }
    })();
}, [module?.id, filters]);

return (
        <div>
      {transformedData.length > 0 && <Grid config={transformedConfig} data={transformedData} autosizeAllColumns={true} id='Grid' ref={gridRef} />}
      {transformedData.length == 0 && !gridLoading && <NoDataAvailable />}
        </div>
    );


有什么办法可以解决这个问题吗?我可以保留一个本地状态变量来跟踪加载,这会很好地工作。但我不想有 2 种加载状态 - 一种在减速器中,一种在本地状态

reactjs redux react-redux
1个回答
0
投票

基本要点是排队的 React 状态更新不会立即处理,而分派到 Redux 存储的操作立即处理。它们都会触发组件重新渲染,但因为 Redux 更新首先被处理,所以它们的更新会在 React 状态更新被处理并触发其重新渲染之前触发重新渲染。

await dmServices.getGridData()
之后,回调函数作用域中没有其他内容是异步的,因此函数体的其余部分将同步处理。

以下是操作和状态更新的一些输出日志记录示例:

// initial state
{gridLoading: false, transformedData: Array(0)}

// effect runs
dispatch loading true                           // <-- update Redux
{gridLoading: true, transformedData: Array(0)}  // <-- Redux store updated

// Got data
enqueue React state update                      // <-- update local State
dispatch loading false                          // <-- update Redux
{gridLoading: false, transformedData: Array(0)} // <-- Redux store updated
{gridLoading: false, transformedData: Array(1)} // <-- Local state updated

作为一点“黑客”,你可以插入一些额外的异步逻辑,以允许 React 处理排队状态更新然后将操作分派到存储。

示例:

useEffect(() => {
  (async () => {
    try {
      dispatch(setLoading(true)); 

      const data = await dmServices.getGridData();

      setTransformedData(data);
      setTransformedConfig(data);

      // "Sleep" for the minimal amount of time and place the rest of
      // this function to the back of the event queue, allows above
      // React state updates to be processed first.
      await new Promise(resolve => {
        setTimeout(resolve, 0);
      });
    } catch (err) {
      console.error('Error while fetching and transforming data:', err);
    } finally {
      dispatch(setLoading(false));
    }
  })();
}, [module?.id, filters]);

以下是操作和状态更新的类似输出日志记录,其中 Redux 更新被推送到事件队列的后面:

// initial state
{gridLoading: false, transformedData: Array(0)}

// effect runs
dispatch loading true                           // <-- update Redux
{gridLoading: true, transformedData: Array(0)}  // <-- Redux store updated

// Got data
enqueue React state update                      // <-- update local State
{gridLoading: true, transformedData: Array(1)}  // <-- Local state updated
dispatch loading false                          // <-- update Redux
{gridLoading: false, transformedData: Array(1)} // <-- Redux store updated
© www.soinside.com 2019 - 2024. All rights reserved.