React只重新渲染一个setState,而不渲染另一个



我正在React中创建一个简单的Tic-Tac-Toe游戏。

目标:每个按钮都有自己的状态。点击按钮后,它应该将状态从"切换到"X",然后将玩家的全局状态更改为"玩家2"。

问题:它只是重新呈现setPlayer((调用,而不是setValue((调用。但如果我去掉setPlayer((,只调用setValue((,那么它就可以按预期工作了。我需要两个setStates来工作并重新渲染,以便在玩家名称更改时显示X。

这是一个指向实时沙盒版本的链接-
https://codesandbox.io/s/ticktacktoe-ozxjm?file=/src/App.js

import './App.css';
import { useState } from 'react';
function App() {
const player1 = "Player 1"
const player2 = "Player 2"
const [player, setPlayer] = useState(player1)

const WhosTurnMessage =()=>(
<div className='message'>
{player}, It's Your Turn
</div>
)

const Buttons =()=>{
const [value, setValue] = useState()
const checkAndSet =()=>{
if (player === player1){
setValue('X')
setPlayer(player2)
}
else {
setValue('O')
setPlayer(player1)
}
}
return (
<div className='grid-item'>
<button className='btn' onClick={()=>checkAndSet()} > 
{value} 
</button>
</div>
)
}
const MapButtons =()=>(
[1,2,3,4,5,6,7,8,9].map( i =>  <Buttons key={`button ${i}`}/>)
)

return (
<div className="App">
<header className="App-header">
<h1>
Tick Tack Toe 
</h1>
</header>
<WhosTurnMessage />

<main>
<div className='grid-container'>
<MapButtons />

</div>
</main>
</div>
);
}
export default App;

代码的问题在于,在呈现App的过程中创建了全新类型的组件。这行不通。例如,每次App渲染时,都会创建一个新的函数Buttons。它可能与原始函数具有相同的文本,但所有反应都知道它与上次不同。因此,由于它是一种不同类型的组件,react会卸载旧组件,然后安装新组件,消除所有状态。

您想要定义的任何组件都需要移动到App之外,这样您只需创建一次,而不是在每次渲染时创建。这肯定包括Buttons,因为它有状态,虽然您可以将WhosTurnMessageMapButtons移出,但我认为它们不应该成为组件。我只需要App计算jsx本身的那些位。

因此,如果你仍然想将组件的一部分分配给局部变量,我建议你这样做:

function App() {
const player1 = "Player 1"
const player2 = "Player 2"
const [player, setPlayer] = useState(player1)

const whosTurnMessage = (
<div className='message'>
{player}, It's Your Turn
</div>
);
const mapButtons = [1,2,3,4,5,6,7,8,9].map( i =>  <Buttons key={`button ${i}`}/>)
return (
<div className="App">
<header className="App-header">
<h1>
Tick Tack Toe 
</h1>
</header>
{whosTurnMessage}
<main>
<div className='grid-container'>
{mapButtons}
</div>
</main>
</div>
)
}
const Buttons = () => {
const [value, setValue] = useState();
// ... same code you already have
}

或者就我个人而言,我会在一行中执行jsx,而不将其分配给变量:

function App() {
const player1 = "Player 1"
const player2 = "Player 2"
const [player, setPlayer] = useState(player1)
return (
<div className="App">
<header className="App-header">
<h1>
Tick Tack Toe 
</h1>
</header>
<div className='message'>
{player}, It's Your Turn
</div>
<main>
<div className='grid-container'>
{[1,2,3,4,5,6,7,8,9].map(i => <Buttons key={`button ${i}`}/>)}
</div>
</main>
</div>
)
}

最新更新