【问题标题】:Correct Way to Update Sate before Async call在异步调用之前更新状态的正确方法
【发布时间】:2022-01-23 07:32:12
【问题描述】:

我正在尝试更新状态以在进行异步调用时显示 ActivityIndi​​cator。

确保IsLoading(true)setResult(null) 在异步调用之前发生的正确方法是什么?

在下面的代码中,setIsLoading 在异步调用之前实际上并未更新,因此 ActivityIndi​​cator 不会出现在 UI 上。我意识到为什么会出现这种情况 (here) 我只是不知道在进行异步调用之前实际确保 ActivityIndi​​cator 显示的推荐方法。

请帮忙。在反应中做到这一点的正确方法是什么?

const MyScreen = () => {
    const [isLoading, setIsLoading] = useState(false);
    const [result, setResult] = useState(null);

    const handlePress = async () => {

        setResult(null);  // reset result
        setIsLoading(true);  // show activity indicator

        const result = await MyAsyncFunc();  // native modules function
        setResult(result);
        setIsLoading(false);  // turn off activity indicator

    }

    return (
        <View style={styles.container}>
            <MyButton title="Run" handlePress={handlePress} disabled={isLoading} />
            {isLoading && <ActivityIndicator size="large" color="#00ff00" />}
            <Text>{result}</Text>
        </View>
    )
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center'
    },
})

【问题讨论】:

    标签: reactjs react-native react-hooks react-state react-async


    【解决方案1】:

    尝试添加useEffect 并在更改result 依赖项时设置isLoading false,如下所示:

    const MyScreen = () => {
        const [isLoading, setIsLoading] = useState(false);
        const [result, setResult] = useState(null);
    
        const handlePress = async () => {
    
            setResult(null);  // reset result
            setIsLoading(true);  // show activity indicator
    
            const result = await MyAsyncFunc();  // native modules function
            setResult(result);
            //setIsLoading(false);  // turn off activity indicator
    
        }
    
        useEffect(() => {
            if(result && isLoading){
                setIsLoading(false);
            }
        }, [isLoading, result])
    
        return (
            <View style={styles.container}>
                <MyButton title="Run" handlePress={handlePress} disabled={isLoading} />
                {isLoading && <ActivityIndicator size="large" color="#00ff00" />}
                <Text>{result}</Text>
            </View>
        )
    }
    

    希望这对你有用

    【讨论】:

    • 感谢您的回复,但我在运行此代码时看到了同样的问题。我认为 idiglove 上面的回答通过将 MyAsyncFunc 放入 useEffect that listens to changes on isLoading. This guarantees that isLoading` 将在 MyAsyncFunc 运行之前更改,从而解决了这个问题。
    【解决方案2】:

    您可以尝试只使用一种状态吗?我认为不需要isLoading。 试试这个

    {!result && <ActivityIndicator size="large" color="#00ff00" />}
    

    编辑:让我们利用 useEffect 来监听 isLoading 是否为真

    ...
    useEffect(() => {
     async function load (){
      if (isLoading) {
       const result = await MyAsyncFunc();  // native modules function
       setResult(result);
       setIsLoading(false);  // turn off activity indicator
      }
     }
     load()
    }, [isLoading])
    
    const handlePress = () => {
       setResult(null);  // reset result
       setIsLoading(true);  // show activity indicator
    }
    

    【讨论】:

    • 当用户第一次访问屏幕时,result 将为空,我会喜欢显示的 ActivityIndi​​cator。他们会按下按钮来触发异步功能。
    • 感谢您的编辑。这样可行!我学到了一些东西:D
    猜你喜欢
    • 2017-02-07
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 2017-04-20
    • 2020-04-21
    • 2017-09-16
    • 2023-01-28
    • 2022-01-10
    相关资源
    最近更新 更多