单击后反应状态不会改变

React state does not change after click

我正在学习反应。 我的代码应该做什么:它应该根据相应行中的星号值呈现正方形。直线有从 1 到 5 的数字,正方形有从 1 到 5 的星星。如果正方形的星星值为 3,那么它应该按照相同的数字呈现。 如果您更改星星值,正方形应在不同的行中呈现。

下面是我的代码。

import react from "react";
import { useState } from "react";

const squares = [
    {'id': 1, 'stars': '5'},
    {'id': 2, 'stars': '4'},
    {'id': 3, 'stars': '3'},
    {'id': 4, 'stars': '3'},
    {'id': 5, 'stars': '5'},
    {'id': 6, 'stars': '4'},
    {'id': 7, 'stars': '2'},
    {'id': 8, 'stars': '1'}
]

const lines = [
    {'id': 1, 'numberName':'One','number': 1},
    {'id': 2, 'numberName':'One','number': 2},
    {'id': 3, 'numberName':'One','number': 3},
    {'id': 4, 'numberName':'One','number': 4},
    {'id': 5, 'numberName':'One','number': 5}
]


function Lines() {
    return (
        lines.map(line => <Line {...line} key={line.id}/>)
    )
}


function Line(props) {
    const [squaresArray, setSquaresArray] = useState(squares)
    function changeSquares(squareId, valueForChange) {
        let oldSquares = squaresArray
        let squareToChange = oldSquares.find(square => square.id == squareId)
        squareToChange.stars = valueForChange
        setSquaresArray(oldSquares)
        console.log(squareId, valueForChange)
    }

    return(
        <div style={{'display':'flex', 'border':'3px red solid', 'padding': '10px'}}>
            {
                squaresArray
                    .filter(square => square.stars == props.number)
                    .map(square => 
                    <Square {...square} changeSquares={changeSquares} squareId={square.id} key={square.id}/>
                )
            }
        </div>  
    )
}

function Square(props) {
    const [stars, setStars] = useState(props.stars)
    return (
        <div style={{'width': '100px','height': '100px','border': 'solid 2px blue','margin-right': '5px'}}>
                <input type='number' name='numb' value={stars} style={{'width':'25px'}} onChange={(e) => {setStars(e.target.value)}}></input>
                <button onClick={() => {props.changeSquares(props.squareId,stars)}} >Save</button>
        </div>
    )
}

function App() {  
    return (
        <Lines lines={lines}/>
    )
}

export default App;

第 61 行有 onClick 函数。此函数应更改页面状态并根据新的平方值重新呈现我的应用程序。但唯一发生的事情是第 40 行的 console.log。我可以看到在第 39 行变量 oldSquares 在单击按钮后正确传递了更新的星号,但方块没有重新渲染。

请帮忙。

状态在 changeSquares 处理程序中发生了变化,数组引用永远不会更新。

function changeSquares(squareId, valueForChange) {
  let oldSquares = squaresArray // <-- reference to state
  let squareToChange = oldSquares.find(square => square.id == squareId)
  squareToChange.stars = valueForChange // <-- mutation!!
  setSquaresArray(oldSquares) // <-- same reference saved back into state
  console.log(squareId, valueForChange)
}

使用功能状态更新从以前的状态更新并将数组的浅表副本创建到新的数组引用中。

function changeSquares(squareId, valueForChange) {
  setSquaresArray(squares => squares.map(square => square.id == squareId
    ? {
      ...square,
      stars: valueForChange
    }
    : square
  ));
  console.log(squareId, valueForChange)
}

这是@drew-reese

建议修改后的解决方案
import react from "react";
import { useState } from "react";

const squares = [
    {'id': 1, 'stars': '5'},
    {'id': 2, 'stars': '4'},
    {'id': 3, 'stars': '3'},
    {'id': 4, 'stars': '3'},
    {'id': 5, 'stars': '5'},
    {'id': 6, 'stars': '4'},
    {'id': 7, 'stars': '2'},
    {'id': 8, 'stars': '1'}
]

const lines = [
    {'id': 1, 'numberName':'One','number': 1},
    {'id': 2, 'numberName':'One','number': 2},
    {'id': 3, 'numberName':'One','number': 3},
    {'id': 4, 'numberName':'One','number': 4},
    {'id': 5, 'numberName':'One','number': 5}
]


function Lines(props) {
    const [squaresArray, setSquaresArray] = useState(squares)
    function changeSquares(squareId, valueForChange) {
        setSquaresArray(squares => squares.map(square => square.id == squareId
            ? {
              ...square,
              stars: valueForChange
            }
            : square
          ))
    }
    return (
        props.lines.map(line => <Line {...line} key={line.id} squaresArray={squaresArray} changeSquares={changeSquares}/>)
    )
}


function Line(props) {


    return(
        <div style={{'display':'flex', 'border':'3px red solid', 'padding': '10px'}}>
            {
                props.squaresArray
                    .filter(square => square.stars == props.number)
                    .map(square => 
                    <Square {...square} changeSquares={props.changeSquares} squareId={square.id} key={square.id}/>
                )
            }
        </div>  
    )
}

function Square(props) {
    const [stars, setStars] = useState(props.stars)
    return (
        <div style={{'width': '100px','height': '100px','border': 'solid 2px blue','marginRight': '5px'}}>
                <input type='number' name='numb' value={stars} style={{'width':'25px'}} onChange={(e) => {setStars(e.target.value)}}></input>
                <button onClick={() => {props.changeSquares(props.squareId,stars)}} >Save</button>
        </div>
    )
}

function App() {  
    return (
        <Lines lines={lines}/>
    )
}

export default App;