Search code examples
javascriptreactjsfrontendtic-tac-toe

React child not updating a variable of parent through function


So I'm learning react at the moment and I've been struggling with this issue.. I'm trying to do tic-tac-toe so I've got this code:

import './App.css';
import { useState } from "react"

const X = 1;
const O = -1;
const EMPTY = 0;

var Square = ({idx, click}) => 
{
    let [val, setVal] = useState(EMPTY);
    return (
        <button onClick={() => {click(setVal, idx);}}>{val}</button>
    )
}

var Logger = ({state}) =>
{
    return (
        <button onClick={() => {console.log(state);}}>log</button>
    )
}

var App = () =>
{
    let [turn, setTurn] = useState(X);
    let state = new Array(9).fill(EMPTY);
    let squares = new Array(9);

    let click = (setValFunc, idx) => 
    {
        setTurn(-turn);
        setValFunc(turn);
        state[idx] = turn;
    }

    for (let i = 0 ; i < 9 ; i++)
    {
        squares[i] = (<Square click={click} idx={i}/>);
    }

    return (
        <>
        <Logger state={state} />
        <div>
            {squares}
        </div>
        </>
    )
}

export default App;

so the squares ARE changing as I click them, but when I click the log button to log the state array to the console, the state array remains all zeros.

what am I missing here?


Solution

  • Your state has to be a React state again. Otherwise, the state you defined inside the App as a local variable only lasts until the next rerender.

    1. Maintain tic-tac-toe state inside a useState hook
    let [state, setState] = useState(new Array(9).fill(EMPTY));
    
    1. Update the click handler accordingly.
      let click = (setValFunc, idx) => {
        setTurn(-turn);
        setValFunc(turn);
        setState((prevState) =>
          prevState.map((item, index) => (index === idx ? turn : item))
        );
      };
    

    Edit agitated-mountain-cfu7o3