自React 18以来Hook不会立即更新数据

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

自从我们从 React 16 更新到 React 18 以来,我们有一个奇怪的行为。 我们有通过钩子确定的数据。

这适用于 React 16,现在在 React 18 中似乎组件仍然首先使用旧数据值进行渲染,然后才更新数据。不幸的是我只有伪代码,但也许有人可以提供帮助。

import * as _ from "lodash";
import * as React from "react";

const useData = (id: string): string[] => {
    const [data, setData] = React.useState(DataManager.selectCurrentDataById(id));

    React.useEffect(() => {
        const handleDataChange = () => {
            const newData = DataManager.selectCurrentDataById(id);

            if (_.isEqual(newData, data)) return;
            console.log("set new data ", newData);
            setData(newData);
        };

        handleDataChange();
        return DataManager.subscribe(handleDataChange);
    }, [data, planId]);

    console.log("return data ", data);
    return data;
};

const MatcherComponent = ({
    id,
}: { id: string }): React.ReactElement<{ id: string }> => {
    const data = useData(id);
    console.log("data ", data);
    
    return (
        <TestType type={data[0]} />
    )
}

const TestType = ({
    type,
}: { type: string }): React.ReactElement<{ type: string }> => {
    console.log("type ", type);

    return (
        <div>{type}</div>
    )
}

以及日志,如果数据发生更改:

// the data was `["type1"]`
// in React 18 it is called twice
set new data "type2"
set new data "type2"

// but then first the child component is re-rendered with the old data and this didn't
// happen in React 16
type "type1"

// then the hook seem to return the new value
return data "type2"
data "type2"

// now the value for the child component is correct
type "type2"
reactjs typescript react-hooks
1个回答
0
投票

它适用于

flushSync

我知道这不是一个好方法,我想了解 React 18 中发生了什么变化。因为 useState 一直是异步的。但在我们更新之前它已经工作了 5 年 :D

import * as _ from "lodash";
import * as React from "react";
import { flushSync } from "react-dom";

const useData = (id: string): string[] => {
    const [data, setData] = React.useState(DataManager.selectCurrentDataById(id));

    React.useEffect(() => {
        const handleDataChange = () => {
            const newData = DataManager.selectCurrentDataById(id);

            if (_.isEqual(newData, data)) return;
            console.log("set new data ", newData);

            flushSync(() => {
                setData(newData);
            });
        };

        handleDataChange();
        return DataManager.subscribe(handleDataChange);
    }, [data, planId]);

    console.log("return data ", data);
    return data;
};
© www.soinside.com 2019 - 2024. All rights reserved.