Search code examples
javascriptreactjsreact-routersemantic-uisemantic-ui-react

React: Manage State of Menu Items and Routes


I'm new to React. I have written a simple React application using Semantic UI, with two menu items, each corresponding to a specific page. I'm not sure how to make each page have its own state, and remember it when navigating the menu.

In index.js:

ReactDOM.render(
    <Main />,
    document.getElementById('root')
);

In Main.jsx:

export default class Main extends Component {
    state = {
        activePageId: 1
    };

    handleSelectPage = (e, { id: selectedPageId }) => {
        this.setState({ activePageId: selectedPageId })
    }

    getActivePage() {
        return (
            <Page id={this.state.activePageId} />
        )
    }

    render () {
        return (
            <Grid divided padded >
                <Grid.Column width={2}>
                    <Menu vertical inverted pointing fluid>
                        <Menu.Item
                            id={1}
                            name='Page 1'
                            active={this.state.activePageId === 1}
                            onClick={this.handleSelectPage}
                            key={1}
                        />
                        <Menu.Item
                            id={2}
                            name='Page 2'
                            active={this.state.activePageId === 2}
                            onClick={this.handleSelectPage}
                            key={2}
                        />
                    </Menu>
                </Grid.Column>
                <Grid.Column width={14}>
                    {this.getActivePage()}
                </Grid.Column>
            </Grid>
        );
    }
}

Finally, in Page.jsx:

export default class Page extends Component {
    state = {
        counter: 0
    };

    increaseCounter = (e) => {
        this.setState({ counter: this.state.counter + 1 });
    }

    render () {
        return (
            <React.Fragment>
                <Header>Page {this.props.id}</Header>
                {this.state.counter}
                <Button primary content='+' onClick={this.increaseCounter}/>
            </React.Fragment>
        );
    }
}

What I can't figure out:

  1. The page id is passed in the props when creating a Page component in getActivePage(). So, that changes every time I navigate the menu. However, the counter is in the state of the Page. That does not change as I navigate the menu. Am I correct to assume there is only one instance of a Page, which is re-rendered when the props (in this case id) change?

  2. It seems like the only way to have a separate counter for each page is to have some sort global state (in a global object) and read from that when rendering a Page. This would mean, however, that I need to call this.forceUpdate inside Page.increaseCounter to re-render the page without re-clicking the menu item. Is that the React way to go?

  3. I'm also thinking about using routing. But, from my preliminary experiments, it seems that, compared to the current scenario, a new Page would be created for each route (is this right?) with its own state. However, that state gets wiped out when navigating between routes, so I still need to keep a global state object and use forceUpdates or so. Any ideas here?

Thanks!


Solution

  • You have to set the counter state inside your Main.jsx component, and then pass the counter state as props to Page.jsx. I recommend you to use functional components and useState hook. Here you can see an example https://codesandbox.io/s/recursing-bardeen-8w58z?file=/src/App.js