【问题标题】:State does not get updated with React hooks状态不会使用 React 钩子更新
【发布时间】:2019-10-29 19:10:03
【问题描述】:

我以为我对钩子中的闭包有所了解。但是,我正在努力解决这个问题。下面的代码是我实际演示代码的一个非常简化的版本。实际上,clickHandler()upload() 要复杂得多。这就是为什么不能将它们组合成一个功能的原因。问题是我无法从上传功能中的状态访问更新的文件数组。但是,如果我对数组使用 ref 它可以工作,我认为这是一种反模式。我还尝试在组件外部声明状态,但没有成功。感谢您的帮助。

import React, { useCallback, useState } from 'react';

const HomeScreen = () => {

    const initialState = {
        error: false,
        files: [],
        totalSize: 0,
        finished: false
    };

    const [state, setState] = useState(initialState);

    const upload = useCallback(() => {
        // At this point state.files is an empty array
        console.log(state.files);
    }, [state]);

    const clickHandler = useCallback(() => {
        const queue = [
            { id: 1, bool: false },
            { id: 2, bool: false }
        ];

        setState((state) => {
            return { ...state, files: queue }
        });

        upload()

    }, [upload]);

    return <button onClick={clickHandler}>Click me</button>;
};

export default HomeScreen;

【问题讨论】:

    标签: javascript reactjs closures react-hooks


    【解决方案1】:

    使用钩子状态更新程序的状态更新是异步的,因此当您从clickHandler 中调用上传时,更新的状态对您不可用。将状态传递给上传方法的最简单解决方案

    import React, { useCallback, useState } from 'react';
    
    const HomeScreen = () => {
    
        const initialState = {
            error: false,
            files: [],
            totalSize: 0,
            finished: false
        };
    
        const [state, setState] = useState(initialState);
    
        const upload = useCallback((updatedState) => {
            // At this point state.files is an empty array
            console.log((updatedState || state).files);
        }, [state]);
    
        const clickHandler = useCallback(() => {
            const queue = [
                { id: 1, bool: false },
                { id: 2, bool: false }
            ];
    
            setState((state) => {
                const updatedState = { ...state, files: queue }
                upload(updatedState )
                return updatedState;
            });
    
            upload()
    
        }, [upload]);
    
        return <button onClick={clickHandler}>Click me</button>;
    };
    
    export default HomeScreen;
    

    【讨论】:

    • 感谢您的快速回答。我也考虑了这一点,并尝试添加一些超时,但这也不起作用。你能解释一下为什么吗?是因为 setTimeout 函数中有一个新的闭包吗?
    【解决方案2】:

    为了让您的upload() 函数能够访问当前状态,必须从useEffect() 调用它。看看这对你有用吗?

    const HomeScreen = () => {
    
        const initialState = {
            error: false,
            files: [],
            totalSize: 0,
            finished: false
        };
        
        const [state, setState] = React.useState(initialState);
    
        const upload = React.useCallback(() => {
            // At this point state.files is an empty array
            console.log(state.files);
        }, [state]);
        
        React.useEffect(()=>{
          state.files.length ? upload() :  null;
        },[state]);
    
        const clickHandler = React.useCallback(() => {
            const queue = [
                { id: 1, bool: false },
                { id: 2, bool: false }
            ];
    
            setState((state) => {
                return { ...state, files: queue }
            });
    
            //upload()
    
        }, [upload]);
    
        return <button onClick={clickHandler}>Click me</button>;
    };
    
    ReactDOM.render(<HomeScreen/>, document.getElementById('root'));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
    <div id="root"></div>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-01
      相关资源
      最近更新 更多