了解React中的钩子设置状态

时间:2020-05-19 10:10:39

标签: javascript reactjs react-hooks

我正在尝试了解React Hooks,并发现了一个问题。我想获取数据,先显示30个条目,然后在后台获取其余数据。 我的逻辑:

useEffect(() => {
    (async function () {
        setIsLoading(true);
        try {
            const data = sortById(await fetch('url'));
            const prep = await prepareData(data, (pageNumber - 1) * elementsPerPage, pageNumber * elementsPerPage);
            setData(prep);
            setIsLoading(false);
            const backgroundData = await fetchMissingData(prep, elementsPerPage)
            setData(backgroundData);
        } catch (e) {
            setError(e);
            setIsLoading(false);
        }
    })();
}, [])

data是来自API的响应,然后我使用它向prepareData中的对象添加了一些内容-该对象本身正在调用另一个API,因此当所有请求完成时

return Promise.all(result).then(done => {
    return done;
})

我正在获取对象数组,但是只有前30个对象充满了我需要的数据。准备好数据后,我将状态data设置为loading并设置为false。在那一刻,数据应该在页面上呈现(?)。然后,我将在后台获取其余数据,而无需再次获取相同的数据(前30个条目),并为我在应用程序中需要的每个条目再次设置data

问题在于,数据是在上一个setData之后呈现的-应用程序正在等待每个提取完成。 我的逻辑错误在哪里?

1 个答案:

答案 0 :(得分:1)

setState,就像在类组件中一样,它是一个异步调用(它不会立即起作用,但会告诉组件应使用不同的上下文再次呈现它)。

例如,--


useEffect(() => {
    (async function () {
        setIsLoading(true);
        try {
          setIsLoading(false);
          ...
        } catch (e) {
            setError(e);
            setIsLoading(false);
        }
    })();
}, [])

isLoading永远不会在其组件中成为true,导致您同时给它truefalse(假设您的代码可以逐行工作,不能保证使用JS,您可能会遇到副作用)。 data遇到了同样的事情,因为您两次致电setData

因此,您可以考虑将效果分成两个效果,而isLoading是第二个效果要运行的标志


  useEffect(() => {
    (async function () {
        setIsLoading(true);
        try {
            const data = sortById(await fetch('url'));
            const prep = await prepareData(data, (pageNumber - 1) * elementsPerPage, pageNumber * elementsPerPage);
            setData(prep);
        } catch (e) {
            setError(e);
            setIsLoading(false);
            // in case there is e at first effect,second effect wont run
        }
    })();
}, [])

useEffect(() => {
    if (isLoading) {
    (async function () {
        try {
                                                        //data now is equal to prep
            const backgroundData = await fetchMissingData(data, elementsPerPage)
            setData(backgroundData);
        } catch (e) {
            setError(e);
        }
    })();
    setIsLoading(false);
   }
}, [isLoading, data])

如果isLoading标志已经用于UI渲染或其他用途,并且不能作为第二效果的标志,则可以创建唯一的isSecondEffectShouldRun或类似的方法(使用{{1} }本身将导致无限循环...)

希望它会有所帮助:)