Хук React useState возвращает старое значение состояния, несмотря на его обновление - PullRequest
0 голосов
/ 25 мая 2019

Я хочу:

  1. загрузить изображение в браузер (я делаю это с помощью React Dropzone. Моя нижеприведенная функция uploadImage запускается при перетаскивании файла в Dropzone.)
  2. считайте изображение как фактическое изображение с помощью API-интерфейса FileReader.
  3. сохраните файл изображения и метаданные изображения в состояние, используя React Hooks.
  4. выполните вызов API, который передает это изображение всервер.

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

Я попытался добавить дополнительные асинхронные элементы ко всем, и я завернул вещи в обещания.Я могу подтвердить, что функция readImage в порядке.Я могу подтвердить последовательность выполнения readImage, saveImage, setGraphic в saveImage, а затем файл console.log в uploadImage, который должен иметь обновленные значения, но не имеет.

  const [graphic, setGraphic] = useState({ ...nullGraphic });

  const readImage = async (img) => {
    const reader = new FileReader();

    return new Promise((resolve, reject) => {
      reader.onerror = () => reader.abort();
      reader.onabort = () => reject(new DOMException('Problem parsing input file.'));
      reader.onload = () => resolve(reader.result);
      reader.readAsDataURL(img);
    });
  };

  const saveImage = async (img) => {
    const imageRead = await readImage(img);

    console.log(imageRead);

    await setGraphic({
      ...graphic,
      image: imageRead,
      imageName: img.name,
      imageType: img.type,
    });

  };


  const uploadImage = async (img) => {
    await saveImage(img);

    console.log(graphic);
});

render() {

  console.log(graphic);

  return( <some dom> )
}

это моя странная последовательность консоли:

Form.js:112 starting saveImage 
Form.js:95 (snipped value of imageRead)
Form.js:237 {snipped updated values of graphic}
Form.js:114 done with saveImage
Form.js:116 {snipped original values of graphic}

Моя теория

Хук useState делает что-то напуганное.Процесс копирует значение при запуске, а не читает его всякий раз, когда читается console.log, поэтому функция uploadImage получает исходные значения ловушки useState за время существования этого процесса.

1 Ответ

0 голосов
/ 25 мая 2019

Может стать понятно, почему это не сработает, если мы упростим все эти магические реакции:

  function withState(initial, fn) {
    function setState(updated) {
       setTimeout(() => fn(updated, setState), 0);
       //...
    }
    setState(initial);
  }

Теперь мы можем проиллюстрировать, что происходит:

  withState(0, (counter, setCount) => {
    console.log("before", counter);
    if(counter < 10) setCount(counter + 1);
    console.log("after", counter);
  });

Как вы можетевидите, setCount не изменит состояние (count) напрямую.Это фактически не изменит локальную переменную count.Поэтому «до» и «после» всегда будут регистрировать одно и то же (до тех пор, пока вы не мутируете counter напрямую).

Вместо этого вызов setCount будет отложен (и сгруппирован в React), итогда он вызовет всю функцию компонента, передающую новый счет.

Поэтому нет смысла пытаться await вызвать setState, также нет смысла регистрировать состояние дои после этого (поскольку это не изменится между).Зарегистрируйте его один раз в компоненте, если вы установите состояние, весь компонент будет выполнен снова, и при регистрации будет записано новое состояние.

...