React: For Loop не обнаруживает изменения состояния хуков

Разработка приложения React, основная функция которого - показывать каждое слово предложения в пределах временного интервала, предварительно установленного пользователем (в основном, быстрое чтение). Я добился этого несколько дней назад, но теперь я пытаюсь реализовать кнопку паузы (чтобы приостановить цикл и получить фактическое слово) и застрял.

Я решил добавить кнопку «Пауза», которая вызывает функцию, которая устанавливает состояние паузы в значение «истина», и внутри моего цикла, если это состояние паузы имеет значение «истина», он выходит из цикла. Но проблема в том, что этот цикл не обнаруживает изменения, у меня есть console.log в строке 18, который всегда регистрирует ложь, хотя я уже нажал кнопку паузы и изменил состояние на 'false' (и это работает потому что я также регистрирую его в useEffect и его loggin 'true')

Итак, мой вопрос: как я могу это решить? Я неправильно использую перехватчики реакции?

Пример кода:

const [time, setTime] = React.useState('500')
const [pause, setPause] = React.useState(false)
const go = async function(){
    let textarray = text.split(' ') //I split my text 
    for(let i = 0; i < textarray.length; i++){ 
        console.log(pause) //This keeps logging false although the change in pauseButton function
        if(pause){
            //Get the actual word => i
            break;
        }
        else{
            setValue(textarray[i]) //Show the actual word
            await timeout(time) //Wait the time
        }
    }
}
const pauseButton = function(){
    setPause(true)
}
function timeout(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

person Maxi Sanchez    schedule 19.05.2021    source источник


Ответы (2)


Думаю, вам стоит немного реорганизовать это. Рассмотрите возможность создания ловушки useInterval () для запуска счетчика. Тогда будет легко запускать и останавливать счетчик.

Используйте ловушку useMemo для результата разделения textArray, чтобы он не пересчитывал каждое обновление.

Затем вы можете просто получить значение textarray [i] в ​​любое время и поместить в свой JSX.

Таким образом, вам вообще не понадобятся другие асинхронные функции.

person Aadmaa    schedule 19.05.2021
comment
Конечно, я попробую использовать этот крючок, спасибо за ответ. Итак, проблема здесь в асинхронной функции? И как я могу приостановить этот хук useInterval ()? Еще раз большое спасибо! - person Maxi Sanchez; 20.05.2021
comment
Компоненты React не являются процедурными по своей природе в том смысле, что вы обычно не меняете их после того, как они отображаются. Обычно проще думать о них как о получающих данные; возможно, сделаю какие-то расчеты; затем возвращаем компонент отображения. Конечно, это не всегда так. Вы можете выполнить асинхронную выборку из API или, в этом случае, установить таймер. Но настроить таймер из-за этого сложнее, чем вы думаете, и это просто помогает использовать простой таймер, основанный на чем-то вроде useInterval, а затем представьте, что каждый тик вы повторно визуализируете компонент с новыми данными. - person Aadmaa; 20.05.2021
comment
Ссылка, которую я поместил в ответ, содержит хороший пример - очень простой. Он устанавливает счетчик, и все, что вам нужно, здесь тоже. - person Aadmaa; 20.05.2021

По сути, вы не понимаете закрытие javascript, поэтому именно по этой причине вы неправильно используете хуки в контексте функции async. Вы не можете получать обновления состояния внутри асинхронной функции на практике. Вы должны использовать useEffects или настраиваемый перехватчик (Живая демоверсия):

import React from "react";
import { useState } from "react";
import { useAsyncCallback } from "use-async-effect2";
import { CPromise } from "c-promise2";

function TestComponent(props) {
  const [text, setText] = useState("one two three four five");
  const [word, setWord] = useState("");

  const go = useAsyncCallback(
    function* (text, delay) {
      const words = text.split(/\s+/);
      for (const word of words) {
        setWord(word);
        yield CPromise.delay(delay);
      }
    },
    { states: true, cancelPrevios: true }
  );

  return (
    <div className="component">
      <div className="caption">useAsyncEffect demo</div>
      <input
        value={text}
        onChange={({ target }) => {
          setText(target.value);
        }}
      />
      <div>{go.error ? go.error.toString() : word}</div>
      {go.pending ? (
        go.paused ? (
          <button className="btn btn-warning" onClick={go.resume}>
            Resume
          </button>
        ) : (
          <button className="btn btn-warning" onClick={go.pause}>
            Pause
          </button>
        )
      ) : (
        <button className="btn btn-warning" onClick={() => go(text, 1000)}>
          Run
        </button>
      )}
      {go.pending && (
        <button className="btn btn-warning" onClick={go.cancel}>
          Cancel request
        </button>
      )}
    </div>
  );
}
person Dmitriy Mozgovoy    schedule 22.05.2021