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

Выдержка из моего кода

 const placeholderText = ["one", "two", "three"];
  const [state, setState] = useState("");

  useEffect(() => {
    placeholderText.map((val, index) =>
      setTimeout(() => {
        setState(placeholderText[index]);
      }, 2000)
    );
  }, []);

  console.log(state);

Когда я пытаюсь ввести в консоль журнал state, через две секунды я получаю сразу три значения. Как я могу устанавливать состояние каждые две секунды и запускать его в цикле, чтобы оно постоянно менялось?

Я создал рабочий пример, используя CodeSandbox . Может ли кто-нибудь помочь?

0
scriobh 28 Фев 2021 в 09:03

4 ответа

Лучший ответ

Вы можете использовать setInterval вместо setTimeout.

Кроме того, мы можем упростить реализацию таким образом, чтобы нам не нужно было хранить фактический текст в состоянии, вместо этого мы могли сохранить индекс. И обновите то же самое через оговоренный интервал.

const {useState, useEffect} = React;

const placeholderText = ["one", "two", "three"];

const Test = () => {
  const [index, setIndex] = useState(0);

  useEffect(() => {
    const timer = () => {
      setIndex(prevIndex => {
        if(prevIndex === placeholderText.length - 1){
          return 0;
        } 
        return prevIndex + 1;
      })
    };
    setInterval(timer, 2000);
    
    //cleanup function in order clear the interval timer
    //when the component unmounts
    return () => { clearInterval(timer); }
  }, []);

  return <p>{placeholderText[index]}</p>
}

ReactDOM.render(<Test />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>

<div id="react"></div>

Здесь, для простоты, я использовал placeholderText вне компонента. Это можно передать как опору компоненту и использовать в компоненте, как показано ниже, и использовать то же, что и зависимость от ловушки useEffect.

ReactDOM.render(<Test text={placeholderText}/>, document.getElementById("react"));
3
Nithish 28 Фев 2021 в 06:29

Вы планируете их все одновременно, чтобы они появлялись одновременно на 2 секунды позже. Я бы сделал так:

import React, { useState, useEffect } from "react";
import "./styles.css";

const delayExecution = (mls) => {
  return new Promise((resolve) => {
    setTimeout(() => resolve("ok"), mls);
  });
};

export default function App() {
  const placeholderText = ["one", "two", "three"];
  const [state, setState] = useState("");

  const changePlaceholder = async () => {
    for (let i = 0; i < placeholderText.length; i++) {
      await delayExecution(2000);
      setState(placeholderText[i]);
    }
  };

  useEffect(() => {
    changePlaceholder();
  }, []);

  return (
    <div className="App">
      <input type="text" placeholder={state} />
    </div>
  );
}

delayExecution разрешает обещание через заданное количество миллисекунд, и поэтому его можно ожидать. Остальное сделает асинхронная функция changePlaceholder.

Песочница: https://codesandbox.io/s/priceless -worker-4v4yc? file = / src / App.js

1
codemonkey 28 Фев 2021 в 06:16

Вы можете использовать setInterval вместо setTimeout для обновления текста каждые 2 секунды. Что-то вроде этого:

export default function App() {
  const placeholderText = ["one", "two", "three"];
  const [state, setState] = useState(0);

  useEffect(() => {
    setInterval(() => {
      setState((s) => (s + 1));
    }, 2000);
  }, []);

  const placeholder = placeholderText[state % placeholderText.length]
  return (
    <div className="App">
      <h1>Hello CodeSandbox {placeholder}</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

0
Yash Joshi 28 Фев 2021 в 06:18

Это происходит из-за закрытия. Если вы хотите менять каждые 2с. Вам нужно setInterval, а не setTimeout. Один из способов решить эту проблему - использовать функцию IIFE, чтобы она использовала каждое значение цикла в setInterval вместо последнего значения цикла. Вот код:

import React, { useState, useEffect } from "react";
import "./styles.css";

export default function App() {
  const placeholderText = ["one", "two", "three"];
  const [state, setState] = useState(0);

  useEffect(() => {
    let interval;

    interval = setInterval(() => {
      setState(function (prev) {
        if (prev === 2) {
          setState(0);
        } else {
          setState(prev + 1);
        }
      });
    }, 2000);

    return () => {
      interval && clearInterval(interval);
    };
  }, []);

  console.log(placeholderText, state);
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      {placeholderText[state]}
    </div>
  );
}

Вот демонстрация: https: // codeandbox.io/s/magical-swirles-83d8m?file=/src/App.js:0-718

0
Shubham Verma 28 Фев 2021 в 06:29