useState(new Map())不起作用,但对象起作用

时间:2020-04-28 20:58:48

标签: reactjs react-hooks

老实说,我不知道这是怎么回事。我有这段代码,在第一次渲染时,它应该获取流行的存储库并将其设置为存储库状态,这将导致重新渲染并在DOM上绘制新的存储库。我使用Map / obj的原因是因为我正在缓存存储库以避免重新获取。 该代码无法按预期工作,没有设置任何新状态,我可以在react dev工具中进行验证。由于某种原因,如果我在devtools中单击Components,状态会更新(?!),但DOM仍未绘制(卡在加载中),这是非常奇怪的行为。

export default () => {
    const [selectedLanguage, setSelectedLanguage] = useState('All');
    const [error, setError] = useState(null);
    const [repos, setRepos] = useState(() => new Map());

    useEffect(() => {
        if (repos.has(selectedLanguage)) return;
        (async () => {
            try {
                const data = await fetchPopularRepos(selectedLanguage);
                setRepos(repos.set(selectedLanguage, data));
            } catch (err) {
                console.warn('Error fetching... ', err);
                setError(err.message);
            }
        })();
    }, [selectedLanguage, repos]);

    const updateLanguage = useCallback(lang => setSelectedLanguage(lang), []);

    const isLoading = () => !repos.has(selectedLanguage) && !error;

    return (
        <>
            <LanguagesNav
                selected={selectedLanguage}
                updateLanguage={updateLanguage}
            />
            {isLoading() && <Loading text="Fetching repos" />}
            {error && <p className="center-text error">{error}</p>}
            {repos.has(selectedLanguage)
                && <ReposGrid repos={repos.get(selectedLanguage)} />}
        </>
    );
};

但是,如果我更改代码以使用对象而不是Map,它可以按预期工作。我在这里想念什么?例如,这有效(使用obj而不是Map)

const Popular = () => {
    const [selectedLanguage, setSelectedLanguage] = useState('All');
    const [error, setError] = useState(null);
    const [repos, setRepos] = useState({});

    useEffect(() => {
        if (repos[selectedLanguage]) return;
        (async () => {
            try {
                const data = await fetchPopularRepos(selectedLanguage);
                setRepos(prev => ({ ...prev, [selectedLanguage]: data }));
            } catch (err) {
                console.warn('Error fetching... ', err);
                setError(err.message);
            }
        })();
    }, [selectedLanguage, repos]);

    const updateLanguage = useCallback(lang => setSelectedLanguage(lang), []);

    const isLoading = () => !repos[selectedLanguage] && !error;

    return (
        <>
            <LanguagesNav
                selected={selectedLanguage}
                updateLanguage={updateLanguage}
            />
            {isLoading() && <Loading text="Fetching repos" />}
            {error && <p className="center-text error">{error}</p>}
            {repos[selectedLanguage]
                && <ReposGrid repos={repos[selectedLanguage]} />}
        </>
    );
};

1 个答案:

答案 0 :(得分:2)

repos.set()变异当前实例并返回它。由于setRepos()看到相同的引用,因此不会触发重新渲染。

代替

setRepos(repos.set(selectedLanguage, data));

您可以使用:

setRepos(prev => new Map([...prev, [selectedLanguage, data]]));