useState (new Map ()) не работает, но объект делает - PullRequest
0 голосов
/ 28 апреля 2020

Я, честно говоря, понятия не имею, что здесь происходит. У меня есть этот код, при первом рендеринге он должен получить популярные репозитории и установить их в состояние репо, что должно вызвать повторный рендеринг и нарисовать новые репозитории на DOM. Причина, по которой я использую Map / obj, заключается в том, что я кеширую репозитории, чтобы избежать повторной выборки. Код не работает должным образом, он не устанавливает никакого нового состояния, и я могу проверить это в инструментах реагирования. По какой-то причине, если я щелкаю по Компонентам в devtools, состояние обновляется (?!), но 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)} />}
        </>
    );
};

Однако , если я изменю код для использования объекта вместо карты, он будет работать как положено. Что мне здесь не хватает? Например, это работает (используя obj вместо карты)

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 Ответ

1 голос
/ 29 апреля 2020

repos.set() изменяет текущий экземпляр и возвращает его. Поскольку setRepos() видит ту же ссылку, она не вызывает повторную визуализацию.

Вместо

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

вы можете использовать:

setRepos(prev => new Map([...prev, [selectedLanguage, data]]));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...