简体   繁体   English

使用 state 道具获取反应组件,以在 state 更改时重新渲染

[英]get react component with state props to rerender upon state change

I can't seem to get a component to rerender in react even though one of its components is a piece of state which gets updates.我似乎无法让一个组件在 react 中重新渲染,即使它的一个组件是 state 的一块得到更新。 The piece of state is board: const [board, setBoard] = useState(""); state 是 board: const [board, setBoard] = useState(""); The component is Table:组件是表:

{board && run? <Table rows = {game.rows} cols = {game.cols} style = {style} board = {board} key = {board} setMoveHistory = {setMoveHistory} moveHistory = {moveHistory} setAState = {setAState} setRun = {setRun}/>:null}

and the board state is changed in the following useEffect:并且板子state改成如下使用效果:

useEffect(() => {
         if(!game) return;
         console.log('useEffect for setting board running');
        setBoard(createFilledArray(game.rows, game.cols, moveHistory.slice(0, tempTurnNum -1)));
        if(tempTurnNum % 2 == 1) setTurnPlayer({username: game.playeroneusername, color: "black"});
        else setTurnPlayer({username: game.playertwousername, color: "white"});
        setRun(true);
        console.log(moveHistory)
         
     },[tempTurnNum, moveHistory, aState])

I have confirmed that the useEffect does correctly update the board state, but the table component won't change to reflect that.我已经确认 useEffect 确实正确更新了板 state,但表格组件不会改变以反映这一点。 Does anyone know how I can get this component to rerender?有谁知道我怎样才能让这个组件重新渲染?

This is my full code:这是我的完整代码:

import React, { useState, useEffect } from "react";
import ReactDOM from 'react-dom';
import socketIOClient from "socket.io-client";
const ENDPOINT = "http://127.0.0.1:4001";
import { useParams } from 'react-router-dom';
import {getGame} from '../apiCalls/index';
import {Table} from './Table'

// function Cross({rowNum, colNum, rows, cols})
// {         let topLeft = "fourth", bottomLeft = "fourth", topRight = "fourth", bottomRight = "fourth";
//          if(rowNum != 0) topRight += " borderLeft";
//          if(colNum != 0) topLeft += " borderBottom";
//          if(rowNum != rows-1) bottomRight += " borderLeft";
//          if(colNum != cols -1) topRight += " borderBottom";
//           return<div className = "tan">
//           <div className = "half">
//             <div className = {topLeft}></div>
//             <div className = {topRight}></div>
//         </div>
//         <div className = "half">
//             <div className = {bottomLeft}></div>
//             <div className = {bottomRight}></div>
//         </div>
//         </div>

// }

// function X()
// {
//     return<div className = "full rotate45">
//                 <div className = "half">
//                     <div className = "fourth borderBottom"></div>
//                     <div className = "fourth borderLeft borderBottom"></div>
//                 </div>
//                 <div className = "half">
//                     <div className = "fourth"></div>
//                     <div className = "fourth borderLeft"></div>
//                 </div>
//             </div>
// }

// function AddX({type}){
//     return<div>
//         {type === "black"?  <X />: <div className = "circle most border"></div>}
//     </div>
// }

// function Edges({rowNum, colNum, rows, check})
// {
//     let classList = "";
//     if(rowNum != rows -1) classList += " borderBottom";
//     if(colNum != 0) classList += " borderLeft"
//     return <td className = {classList} > 
//         {check.occupied?<AddX type = {check.type}/> :null}
//     </td>
// }

// function Cell({style, rowNum, colNum, rows, cols, board, setMoveHistory, moveHistory, setRState, setRun})
// {
//     let check = board[rowNum][colNum];
//     return <>
//         {style === "go"? <td onClick = {() => {
//             console.log("clicked")
//             //setRun(false);
//             let history = moveHistory;
//             history.push({row: rowNum, col: colNum});
//             setMoveHistory(history);
//             setRState(Math.random());
//         }}>
//             <Cross rowNum = {rowNum} colNum = {colNum} rows = {rows} cols = {cols}/>
//             {check.occupied? <div className = {"circle full top shine " + check.type}></div>:null}
//             </td>
//         :
//     <Edges rowNum = {rowNum} colNum = {colNum} rows = {rows} check = {check}></Edges>}</>
// }
// function Row({cols, rows, style, rowNum, board, setMoveHistory, moveHistory, setTstate, setRun})
// {
//     let row = [];
//     const [rState, setRState] = useState("");
//     useEffect(() => {setTstate(Math.random())}, [rState])
//     for(let i = 0; i< cols; i++)
//     {
//         row.push(<Cell style = {style} key = {i} rowNum = {rowNum} colNum = {i} rows = {rows} cols = {cols} board = {board} setMoveHistory = {setMoveHistory} moveHistory = {moveHistory} setRState = {setRState} setRun = {setRun}/>)
//     }
//     return <tr>{row}</tr>
// }

// function Table({rows, cols, style, board, setMoveHistory, moveHistory, setAState, setRun})
// {
//     const [tState, setTstate] = useState("");
//     useEffect(() => {setAState(Math.random())}, [tState])
//     let table = [];
//     for(let i = 0; i< rows; i++)
//     {
//         table.push(<Row rows = {rows} cols = {cols} style = {style} rowNum = {i} board = {board} key = {i} setMoveHistory = {setMoveHistory} moveHistory = {moveHistory} setTstate = {setTstate} setRun = {setRun}/>)
//     }
//     return <table cellSpacing = {0} cellPadding = {0}><tbody>{table}</tbody></table>
// }

function createBlankArray(rows, cols){
    let arr = [];
    for(let i = 0; i < rows; i++)
    {
        let r = [];
        for(let j = 0; j < cols; j++)
        {
            r.push({occupied:false, type: "none"})
        }
        arr.push(r);
    }
    return arr;
}

function createFilledArray(rows, cols, history)
{
    let arr1 = createBlankArray(rows, cols);
    history.forEach((move, indx) => {
        let turn;
        if(indx % 2 == 0) turn = "black";
        else turn = "white";
        arr1[move.row][move.col] = {occupied:true, type: turn}
    });
    return arr1;
}

function Renju({token})
{
    const {gameId} = useParams();
    const [game, setGame] = useState(null);
    const [moveHistory, setMoveHistory] = useState([]);
    const [style, setStyle] = useState("go");
    const [board, setBoard] = useState("");
    const [run, setRun] = useState(0);
    const [isCurrent, setIsCurrent] = useState(true);
    const [turnNum, setTurnNum] = useState(0);
    const [tempTurnNum, setTempTurnNum] = useState(0);
    const [turnPlayer, setTurnPlayer] = useState("");
    const [aState, setAState] = useState("");

    useEffect(() => {console.log("aState", aState)}, [aState])
  
    useEffect(() => {
        const fetchData = async () => {
          console.log('useEffect for setting game running');
          if(!token) return;
          console.log(gameId)
          const game = await getGame(gameId);
          console.log(game)
          if(game){ 
            setGame(game);
            if(game.movehistory) {
                console.log(JSON.parse(game.movehistory))
                setMoveHistory(JSON.parse(game.movehistory))
            }
          }
    }
        fetchData();
      }, [token]);

     useEffect(() => {
         if(!game) return;
        console.log('useEffect for setting turn Number running')
        setTurnNum(moveHistory.length + 1);
        setTempTurnNum(moveHistory.length + 1);
        if(moveHistory.length % 2 == 0) setTurnPlayer({username: game.playeroneusername, color: "black"});
        else setTurnPlayer({username: game.playertwousername, color: "white"});
     }, [game, moveHistory, board.length])

     useEffect(() => {
         if(!game) return;
         console.log('useEffect for setting board running');
        setBoard(createFilledArray(game.rows, game.cols, moveHistory.slice(0, tempTurnNum -1)));
        if(tempTurnNum % 2 == 1) setTurnPlayer({username: game.playeroneusername, color: "black"});
        else setTurnPlayer({username: game.playertwousername, color: "white"});
        setRun(true);
        console.log(moveHistory)
         
     },[tempTurnNum, moveHistory, aState])
    

    return<div>
       <h1>Renju</h1>
       <h3>Turn {tempTurnNum} {turnPlayer.color}'s({turnPlayer.username}'s) move</h3>
       {!isCurrent && tempTurnNum === turnNum? <h3>(Current Board)</h3>: !isCurrent? <h3>
        {turnNum - tempTurnNum} moves away from current Board.
       </h3>: null}
       <label>Board style: </label>
       <select value = {style} onChange = {(event) =>{setStyle(event.target.value)}}>
           <option value = "go"> Go Board </option>
           <option value = "x"> Tic-Tac-Toe </option>
       </select>
       <br />
       <label>View Past/ Future Board States</label>
       <input type = "checkbox" checked = {!isCurrent} onChange = {
           event => {setIsCurrent(!event.target.checked)
           setTempTurnNum(turnNum);
       }} />
       {isCurrent? null: <div> 
                <button name = "backbutton" disabled = {tempTurnNum == 1} onClick = {() => {setTempTurnNum(tempTurnNum -1)}}>&#x2190;</button>
                <button name = "forwardbutton" disabled = {tempTurnNum === turnNum} onClick = {() => {setTempTurnNum(tempTurnNum +1)}}>&#x2192;</button>
               </div>}
       {board && run? <Table rows = {game.rows} cols = {game.cols} style = {style} board = {board} key = {board} setMoveHistory = {setMoveHistory} moveHistory = {moveHistory} setAState = {setAState} setRun = {setRun}/>:null}
    </div>
}

export default Renju;
import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { useParams } from 'react-router-dom';
function Cross({rowNum, colNum, rows, cols})
{         let topLeft = "fourth", bottomLeft = "fourth", topRight = "fourth", bottomRight = "fourth";
         if(rowNum != 0) topRight += " borderLeft";
         if(colNum != 0) topLeft += " borderBottom";
         if(rowNum != rows-1) bottomRight += " borderLeft";
         if(colNum != cols -1) topRight += " borderBottom";
          return<div className = "tan">
          <div className = "half">
            <div className = {topLeft}></div>
            <div className = {topRight}></div>
        </div>
        <div className = "half">
            <div className = {bottomLeft}></div>
            <div className = {bottomRight}></div>
        </div>
        </div>

}

function X()
{
    return<div className = "full rotate45">
                <div className = "half">
                    <div className = "fourth borderBottom"></div>
                    <div className = "fourth borderLeft borderBottom"></div>
                </div>
                <div className = "half">
                    <div className = "fourth"></div>
                    <div className = "fourth borderLeft"></div>
                </div>
            </div>
}

function AddX({type}){
    return<div>
        {type === "black"?  <X />: <div className = "circle most border"></div>}
    </div>
}

function Edges({rowNum, colNum, rows, check})
{
    let classList = "";
    if(rowNum != rows -1) classList += " borderBottom";
    if(colNum != 0) classList += " borderLeft"
    return <td className = {classList} > 
        {check.occupied?<AddX type = {check.type}/> :null}
    </td>
}

function Cell({style, rowNum, colNum, rows, cols, board, setMoveHistory, moveHistory})
{
    let navigate = useNavigate();
    const {gameId} = useParams();
    let check = board[rowNum][colNum];
    return <>
        {style === "go"? <td onClick = {() => {
            console.log("clicked")
            //setRun(false);
            let history = moveHistory;
            history.push({row: rowNum, col: colNum});
            setMoveHistory(history);
            const address = '../renju/' + gameId
            navigate(address);
        }}>
            <Cross rowNum = {rowNum} colNum = {colNum} rows = {rows} cols = {cols}/>
            {check.occupied? <div className = {"circle full top shine " + check.type}></div>:null}
            </td>
        :
    <Edges rowNum = {rowNum} colNum = {colNum} rows = {rows} check = {check}></Edges>}</>
}
function Row({cols, rows, style, rowNum, board, setMoveHistory, moveHistory})
{
    let row = [];
    for(let i = 0; i< cols; i++)
    {
        row.push(<Cell style = {style} key = {i} rowNum = {rowNum} colNum = {i} rows = {rows} cols = {cols} board = {board} setMoveHistory = {setMoveHistory} moveHistory = {moveHistory}/>)
    }
    return <tr>{row}</tr>
}

function Table({rows, cols, style, board, setMoveHistory, moveHistory})
{
    let table = [];
    for(let i = 0; i< rows; i++)
    {
        table.push(<Row rows = {rows} cols = {cols} style = {style} rowNum = {i} board = {board} key = {i} setMoveHistory = {setMoveHistory} moveHistory = {moveHistory} />)
    }
    return <table cellSpacing = {0} cellPadding = {0}><tbody>{table}</tbody></table>
}

export {Table};

Right now useEffect isn't called when a cell is clicked, but if I make it so that moveHistory is a piece of state in each of Table's descendents that should fix that problem现在单击单元格时不会调用 useEffect ,但是如果我这样做,那么 moveHistory 是 Table 的每个后代中的 state 的一部分,应该可以解决该问题

Since posting this I altered my table so that it was mostly in one component which simplified things.自从发布此内容后,我更改了我的表格,使其主要集中在一个组件中,从而简化了事情。

I figured out my problem was that I didn't adjust the variable which set how many moves the board should look at when I changed the board(I had this variable so you could see the past state of the board/history of the game), meaning that even though the history changed, it didn't change the actual board state, oops.我发现我的问题是我没有调整设置当我更换棋盘时棋盘应该看多少步的变量(我有这个变量,所以你可以看到棋盘过去的 state/游戏历史) ,这意味着即使历史发生了变化,它并没有改变实际的板 state,哎呀。 Thats why it didn't reRender.这就是它没有重新渲染的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM