REACT,有一个滚动 num 1-10 的变量,并在 JSX 的 return 语句中连接该变量。数字在屏幕上呈现之前滚动 2 倍

REACT, have a variable that rolls a num 1-10 and concatenating that variable in return statement in JSX. Number is rolled 2x before rendered on screen

在学习 React 的过程中,只是为了练习目的构建了一个简单的猜数游戏

在我的代码中,我有一个名为 'Game' 和 'const roll = Math.floor(Math.random() * 10 + 1)' 的组件,用于滚动 1-10 之间的随机数并通过 console.log 验证滚动,以便我可以看到数字显示在控制台上。

然后我在我的 return 语句中使用 {roll} 稍后在我的 App.js 文件中实例化(App.js 未在下面显示)

唯一的问题是使用 console.log(roll) 时滚动的随机数与在我的 return 语句 'The number rolled is {roll}'[=12= 中呈现在屏幕上的数字不同]

这是为什么?我在 vanilla JavaScript 中从未遇到过这个问题,但似乎滚动发生了两次,而不是在 'const roll'

中采用初始值

谁能解释为什么会这样以及如何解决这个问题?感谢我能得到的任何帮助

import React, {useState} from "react";

const Game = () => {
    const roll = Math.floor(Math.random() * 10 + 1);
    console.log(roll);

    const guess = () => {
        let inputGuess = document.querySelector('.input');
        console.log(inputGuess.value);
    }

    const [lives, setLives] = useState(5);

    return (
        <React.Fragment>
            <h1 className='header'>Guess the number!</h1>
            <p className='roll'>The number rolled is <strong>{roll}</strong></p>
            <p className='lives'><strong>{lives}</strong> lives remaining</p>
            <p className='message'>Enter a number between 1-10</p>
            <input type='text' className='input'></input>
            <button className='guess' onClick={guess}>Guess</button>
        </React.Fragment>
    )
}

export default Game;

在开发模式下,有意 React invokes function component bodies (and other lifecycle methods) twice 以帮助识别副作用:

Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following functions:

  • Class 组件构造函数、render 和 shouldComponentUpdate 方法
  • Class 组件静态 getDerivedStateFromProps 方法
  • 函数组件体
  • 状态更新函数(setState 的第一个参数)
  • 传递给 useState、useMemo 或 useReducer 的函数

添加到 ray hatfield 的答案中

您应该考虑,您的 roll 变量将在每次渲染时重新声明(因此是一个新的随机数)。每当更新 lives 状态以及父组件重新呈现时,组件都会重新呈现。

为了防止重新分配 roll 变量,您应该将它放在自己的 useState 钩子中。

尝试:

const Game = () => {
    const roll = Math.floor(Math.random() * 10 + 1);
    const [roll2, setRoll] = React.useState(Math.floor(Math.random() * 10 + 1));
    console.log('Without useState: ', roll);
    console.log('With useState: ', roll2);

    const guess = () => {
        let inputGuess = document.querySelector('.input');
        console.log(inputGuess.value);
    }

    const [lives, setLives] = React.useState(5);

    return (
        <React.Fragment>
            <h1 className='header'>Guess the number!</h1>
            <p className='roll'>The number rolled is <strong>{roll}</strong></p>
            <p className='lives'><strong>{lives}</strong> lives remaining</p>
            <p className='message'>Enter a number between 1-10</p>
            <input type='text' className='input'></input>
            <button className='guess' onClick={guess}>Guess</button>
        </React.Fragment>
    )
};

const App = () => {
    console.log('re-rendering App');
    const [state, setState] = React.useState(0);

    // we are faking an update to the parent component
    React.useEffect(() => {
        setInterval(() => setState((prev) => ++prev), [2000]);
    }, []);
    
    return <div><Game /></div>;
}
ReactDOM.render(<App />, document.getElementById('app'));
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin ></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin ></script>
<div id="app"></div>