Search code examples
javascriptreactjscomponentsstate

Optimal way to set state of another component from


there's a few posts explaining how to update state from another component but I'm still unable to parse the solution for my particular problem. I want the submit button in my SideBar.js component to trigger nextProblem() in my tableA.js component when it is clicked. This will cause the state of tableA.js to change as problemNum goes from 1 to 2, generating a different form. I can't import SideBar.js component into my tableA.js due to my design layout though! SideBar.js also contains images. Any ideas?

I'm using a CSS grid for the layout of my page:

    grid-template-areas:
        "navbar navbar navbar navbar"
        "sidebar tableA ... ..."
        "sidebar tableA ... ..."
        "sidebar tableA ... ..."

I'm using App.js to route to the pages:

function App() {
  return (
      <Router>
        <div className="App">
          <Routes>
              <Route path={"/"} exact element={<MainPage/>}/>
              <Route path={"/gamePage"} exact element={<GamePage/>}/>
          </Routes>
        </div>
      </Router>
  );
}

export default App;

I created a SideBar.js component that contains a logo at the top and a submit button at the bottom:

class SideBar extends Component {
    componentDidMount() {

    }
    render() {
        return (
            <div className={"sidebar"}>
                <div className={"logo_group"}>
                    <img className={"some_logo"} src={logo}/>
                </div>
                <div className={"nav_group"}>
                    <button className={"home"}/>
                    <button className={"about"}/>
                </div>
                <img className={"an_image"} src={someImage}/>
                <div className={"button_group"}>
                    <button className={"submit_button"} onClick={() => nextProblem()}>Submit</button>
                </div>
            </div>
         )
    }
}
export default SideBar

and a tableA.js component with a function nextProblem() that changes the state of the component:

class tableA extends Component {
    state = {
        problemNum: 1,
        problemStatus: 'unsolved',
        userAnswer: []
    };

    nextProblem = () => {
        this.setState(state => ({
            problemNum: state.problemNum + 1,
        }))
    }

    componentDidMount() {}

    render() {
        return (
            <div>
                <form>
                     ...depends on the state of the problem number
                </form>
            </div>
        )
    }

export default tableA

I then consolidate everything in GamePage.js:

const GamePage= () => {
    return (
        <div className={"gamepage-container"}>
            <div className={"navbar"}>
                <NavBar></NavBar>
            </div>
            <div className={"sidebar"}>
                <SideBar></SideBar>
            </div>
            <div className={"tableA"}>
                <TableA></TableA>
            </div>
            ...
        </div>
      )
}

export default GamePage


Solution

  • i'd propably go the approach of letting the gamepage handle the state and such and send down the problem and the update function down the components as props. Depending on how big this thing will grow you could also use a centralized store.

    const GamePage= () => {
        const [problem, setPropblem] = useState(0)
    
        return (
            <div className={"gamepage-container"}>
                <div className={"navbar"}>
                    <NavBar></NavBar>
                </div>
                <div className={"sidebar"}>
                    <SideBar 
                        onSetNext={() => setProblem(problem + 1)}
                    ></SideBar>
                </div>
                <div className={"tableA"}>
                    <TableA
                        problem={problem}
                    ></TableA>
                </div>
                ...
            </div>
          )
    }
    
    export default GamePage
    

    and in your sidebar the button becomes

    <button className={"submit_button"} onClick={() => this.props.onSetNext()}>Submit</button>
    

    similarly you access the props.propblem instead of state in your table.