Состояние реакции обновлено правильно, кроме функции gamel oop - PullRequest
0 голосов
/ 18 июня 2020

У меня есть очень простой код реакции, объявляющий переменную состояния с именем money с помощью хука useState .

Затем я запускаю gamel oop для запуска один раз, используя хук useEffect .

Внутри этой игры oop я просто увеличиваю значение переменной состояния денег.

import React, { useState, useEffect } from "react";

export default function Game() {
  // declare one state variable
  const [money, setMoney] = useState(100);

  // start gameloop
  useEffect(() => {
    let anim = requestAnimationFrame(gameloop);

    return () => {
      cancelAnimationFrame(anim);
    };
  }, []);

  function gameloop() {
    setMoney(money => money + 1);
    console.log(money); // always returns 100
    requestAnimationFrame(gameloop);
  }

  return (
    <div>
      <div>{money}</div>
    </div>
  );
}

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

Однако внутри функции gamel oop, когда я выполняю console.log(money); , он всегда печатает 100 .

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

Есть идеи, что я здесь делаю не так?

Ответы [ 2 ]

0 голосов
/ 18 июня 2020

Функция gameloop была объявлена, когда money имело значение 100 при начальной визуализации. Именно эта функция, в области видимости которой переменная money по-прежнему равна 100, вызывается в каждом кадре, а не функция, которая создается при каждом рендеринге (которая имеет "самое свежее" значение в money).

Чтобы синхронизировать c два расписания (rAF против React), вы можете использовать хук useRef. Например, воссоздайте gamel oop на каждом рендере:

let gameloop = useRef();
gameloop.current = function() {
  ...
  requestAnimationFrame(gameloop.current);
}

По сути, ловушка useRef создает своего рода свойство экземпляра на функциональном компоненте.

0 голосов
/ 18 июня 2020

Вы не делаете ничего плохого. Это потому, что состояние React обновляется асинхронно. Это означает, что когда вы хотите, чтобы консоль регистрировала состояние переменной money, это состояние еще не обновляется. Что вы можете сделать, так это зарегистрировать его с помощью функции useEffect, примерно так:

useEffect(() => {
    let anim = requestAnimationFrame(gameloop);
    console.log(money);    
    return () => {
      cancelAnimationFrame(anim);
    };
  }, [money]);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...