Вызов `useVal` несколько раз в одной функции с массивами - неожиданное поведение - PullRequest
0 голосов
/ 21 февраля 2019

Я вызываю свою функцию useArr несколько раз в течение одного вызова функции.При каждом вызове useArr я добавляю новое значение к существующей функции arr.Я поражаю каждый вызов функцией pause.

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

Чтобы дать некоторый контекст относительно того, почему я пишу этот нетрадиционный код, я пытаюсь смоделироватькак websocket будет взаимодействовать с приложением, если кому-то интересно:)

const App = () => {
  const [arr, useArr] = useState([])
  return (
    <div>
      {arr}
      <button onClick={increment}>Click meh</button>
    </div>
  )
  async function increment() {
    useArr([...arr, 'a'])
    await pause()
    useArr([...arr, 'b'])
    await pause()
    useArr([...arr, 'c'])
    await pause()
    useArr([...arr, 'd'])
    await pause()
    useArr([...arr, 'e'])
    await pause()
  }
  async function pause() {
    return new Promise(_=>setTimeout(_, 500))
  }
}

export { App }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

1 Ответ

0 голосов
/ 21 февраля 2019

tl; dr: Вы должны использовать функциональное обновление синтаксис .

Это больше касается понимания замыканий JavaScript, чем хуков.Чтобы продемонстрировать, что происходит, вот код, основанный на вашем методе increment, но без каких-либо хуков - просто обычный JavaScript.

  async function increment() {
    const arr = [];
    let nextArr = undefined;
    nextArr = [...arr, 'a'];
    await pause()
    nextArr = [...arr, 'b'];
    await pause()
    nextArr = [...arr, 'c'];
    await pause()
    nextArr = [...arr, 'd'];
    await pause()
    nextArr = [...arr, 'e'];
    await pause()
  }

В конце этой функции, что вы ожидаетезначение nextArr будет?['a', 'b', 'c', 'd', 'e'] или ['e'] (подсказка: вы уже видели результат в своем приложении)

nextArr представляет то, что вы передаете своему установщику состояния.

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

То, что вы хотели сделать, выглядит примерно так:

  async function increment() {
    const arr = [];
    let nextArr = undefined;
    nextArr = [...arr, 'a'];
    await pause()
    nextArr = [...nextArr, 'b'];
    await pause()
    nextArr = [...nextArr, 'c'];
    await pause()
    nextArr = [...nextArr, 'd'];
    await pause()
    nextArr = [...nextArr, 'e'];
    await pause()
  }

Этот код использует предыдущее значениесоздать следующее значение.Синтаксис функционального обновления может использоваться для получения этого эффекта.С учетом синтаксиса функционального обновления и изменения имен, которые я предложил, ваша функция increment будет выглядеть следующим образом:

  async function increment() {
    setArr(prevArr => [...prevArr, 'a'])
    await pause()
    setArr(prevArr => [...prevArr, 'b'])
    await pause()
    setArr(prevArr => [...prevArr, 'c'])
    await pause()
    setArr(prevArr => [...prevArr, 'd'])
    await pause()
    setArr(prevArr => [...prevArr, 'e'])
    await pause()
  }

Edit array functional state update

...