Проблемы с последовательной установкой объекта состояния в перехватчиках реагирования - PullRequest
1 голос
/ 08 марта 2019

Я начинаю использовать реагирующие хуки, и я решаю поместить объект вместо переменной в функцию useState:

const [foo, setFoo] = useState({
    term: '',
    loading: false,
    ...
});

, но позже, когда я хочу обновить его

const onChange = (e) => { 

    const { value } = e.target;

    setFoo({ ...foo, term: value });

    if(value) setFoo({ ...foo, loading: true });

    ...

}

...

return (
   ...
   <input onChange={onChange} value={term} />
   ...
) 

1. Почему во втором setFoo когда я проверяю объект foo, я всегда получаю term свойство, равное '' точно так же, как исходное значение, а входные данные небыть в курсе набранных символов?

- Когда я удаляю вторую setFoo, она работает, поэтому я думаю, что setFoo является асинхронным, но как решить эту проблему?.

- Я знаю, что мы можем обойти эту проблему, сумев позвонить setFoo только один раз, но я хочу знать другие решения?

2. Почему такого рода проблемы никогда не возникали в redux?

Ответы [ 3 ]

2 голосов
/ 08 марта 2019

Решение: используйте один setFoo вот так:

const onChange = (e) => { 

    const { value } = e.target;

    setFoo({ term: value, loading: !!value });

    ...

}

!! означает «преобразовать в логическое значение».

1 голос
/ 08 марта 2019

1. Возможно, потому что вам нужно уничтожить foo вместо state

setFoo({ ...foo, term: value });

работает useState пример

2. Посмотрите на дополнительные крючки, особенно useReducer

useReducer обычно предпочтительнее, чем useState, когда у вас логика сложного состояния, которая включает в себя несколько значений, или когда следующее состояние зависит от предыдущего.

И ваш код может стать:

const reducer = (state, action) {
    switch(action.type) {
       case 'loading':
         return { ...state, loading: true };
       case 'loaded':
       default:
         return { ...state, loading: false };
    }
}

const initialState = {
  term: '',
  loading: false,
}
const [state, dispatch] = useReducer(reducer, initialState);
dispatch({
   type: e.target.value ? 'loaded' : 'loading'
});

работает useReducer пример на CodeSandbox

1 голос
/ 08 марта 2019

Вы можете решить проблему, вызвав setFoo только один раз со всеми новыми парами ключ-значение, например:

const onChange = (e) => { 

    const { value } = e.target;
    const loading = value ? true : false;
    setFoo({ ...state, term: value, loading });
    ....
}

Обновление:

Для сложного обновления состояния и большего контроля над этой частью вы можете использовать useReducer и написать отдельный редуктор для обновления состояния.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...