Состояние не обновляется с помощью React-хуков - PullRequest
1 голос
/ 15 июня 2019

Мне показалось, что я завязал затвор в крючках.Тем не менее, я борюсь с этим.Код ниже - очень упрощенная версия моего реального кода для демонстрации.На самом деле clickHandler() и upload() гораздо сложнее.Вот почему нельзя объединить их в одну функцию.Проблема в том, что я не могу получить доступ к обновленному массиву файлов из состояния функции загрузки.Если я использую ссылку для массива, он работает, однако, я думаю, что это антипаттерн.Я также попытался объявить состояние вне компонента, который не работал.Спасибо за вашу помощь.

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;

Ответы [ 2 ]

0 голосов
/ 17 июня 2019

Чтобы ваша функция 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>
0 голосов
/ 15 июня 2019
Обновление состояния

с использованием средства обновления состояния ловушек является асинхронным, и поэтому при вызове загрузки из 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;
...