'react using states to toggle sidebar

I have a working css/html/javascript example of a sidebar that can be toggled to open/close:

https://jsfiddle.net/martinradio/2dx4o18q/4/

I'm trying to convert this example to React, and since my jsfiddle adds/removes a css class in order to toggle the sidebar, im trying to recreate the functionality using states.

Since my sidebar will be on every page of my site, I'm trying to make it so I can pass it a component that will get rendered inside content.

For example, my component below: SidebarColors.js will take another component as an import like so:

<Route exact path="/rendertune" element={ <SidebarColors> <myOtherComponent/> </SidebarColors> } />

Then in my file below, it will get rendered as {children} in the webpage.

But in my file below, none of the state setting works.

import React from 'react'
import '../css/SidebarColors.css';

var isSidebarOpen = false;

function sideNavClicked() {
    isSidebarOpen ? closeNav() : openNav();
}

function openNav() {
    isSidebarOpen = true;
    //this.setShowSidebar(true)
    //document.getElementById('mySidebar').classList.add('sidebar-show');
    //this.setMainShow(true)
    //document.getElementById('main').classList.add('main-show');
}

function closeNav() {
    isSidebarOpen = false;
    //this.setShowSidebar(false)
    //document.getElementById('mySidebar').classList.remove('sidebar-show');
    //this.setMainShow(false)
    //document.getElementById('main').classList.remove('main-show');
}

function toggleMenuItem(element) {
    //console.log('toggleMenuItem')
    //this.setSidebarMenuToggle(false)
    // document.getElementById(element.dataset.ulid).classList.toggle("ul-show");
}


const SidebarColors = ({ children }) => {

    const [showSidebar, setShowSidebar] = React.useState(true);
    const [mainShow, setMainShow] = React.useState(true);

    return (
        <>
            <div>
                <button onClick={() => setShowSidebar(true)}>debug button: open sidebar</button>

                <div className="main-content">
                    <div id="mySidebar" className={"sidebar super-animation " + (showSidebar ? "sidebar-show" : "")}>
                        <a href="" className="closebtn" onClick={closeNav}>×</a>
                        <a href="#">About</a>
                        <a data-ulid="expand_this" onClick={toggleMenuItem(this)} href="#">Expand This ▼</a>
                        <ul id="expand_this">
                            <li><a href="#">Coffee</a></li>
                            <li><a href="#">Coverage</a></li>
                        </ul>

                        <a href="#">Clients</a>
                        <a href="#">Contact</a>
                    </div>

                    <div id="main" className={"super-animation" + (mainShow ? "main-show" : "")}>
                        
                        <p>Below is a button to open sidebar</p>
                        <button className="openbtn" onClick={sideNavClicked}>☰</button>

                        <p>main content below</p>
                        {children}
                    
                    </div>
                </div>


            </div>


        </>
    )
}

export default SidebarColors

I couldn't use a constructor and instead had to use React.useState, but calling the functions (for example setShowSidebar(true) ) which should cause a class to be added to an element and get rendered, cause no changes to the page.

Am I missing something for how to use state variables to cause a css class to get added/removed for my element? Thanks

edit1 Updated code based on comment, but clicking my button which calls openNav() throws an error due to Assignment To Constant Variable

import React from 'react'
import '../css/SidebarColors.css';

const SidebarColors = ({ children }) => {

    const [isSidebarOpen, setIsSidebarOpen] = React.useState(false);
    const [showSidebar, setShowSidebar] = React.useState(true);
    const [mainShow, setMainShow] = React.useState(true);

    function sideNavClicked() {
        console.log('isSidebarOpen = ', isSidebarOpen)
        isSidebarOpen ? closeNav() : openNav();
    }

    function openNav() {
        console.log('openNav')
        isSidebarOpen = true;
        this.setShowSidebar(true)
        //document.getElementById('mySidebar').classList.add('sidebar-         show');
        //this.setMainShow(true)
        //document.getElementById('main').classList.add('main-show');
    }

    function closeNav() {
        console.log('closeNav')
        isSidebarOpen = false;
        this.setShowSidebar(false)
        //document.getElementById('mySidebar').classList.remove('sidebar-         show');
        //this.setMainShow(false)
        //document.getElementById('main').classList.remove('main-show');
    }

    function toggleMenuItem(element) {
        //console.log('toggleMenuItem')
        //this.setSidebarMenuToggle(false)
        // 
        //document.getElementById(element.dataset.ulid).classList.toggle("ul-show");
    }

    return (
        <>
            <div>
                <button onClick={() => setShowSidebar(true)}>debug button: open sidebar</button>

                <div className="main-content">
                    <div id="mySidebar" className={"sidebar super-animation " + (showSidebar ? "sidebar-show" : "")}>
                        <a href="" className="closebtn" onClick={closeNav}>×</a>
                        <a href="#">About</a>
                        <a data-ulid="expand_this" onClick={toggleMenuItem(this)} href="#">Expand This ▼</a>
                        <ul id="expand_this">
                            <li><a href="#">Coffee</a></li>
                            <li><a href="#">Coverage</a></li>
                        </ul>

                        <a href="#">Clients</a>
                        <a href="#">Contact</a>
                    </div>

                    <div id="main" className={"super-animation" + (mainShow ? "main-show" : "")}>

                        <p>Below is a button to open sidebar</p>
                        <button className="openbtn" onClick={sideNavClicked}>☰</button>

                        <p>main content below</p>
                        {children}

                    </div>
                </div>


            </div>


        </>
    )
}

export default SidebarColors


Solution 1:[1]

Its because you are using variables to set state. React components do not re-render when using regular variables. If you want your page to be updated with UI components then it must be maintained in state. Also you are using this keywords in a functional component. Those should be removed.

const SidebarColors = ({ children }) => {
  const [isSidebarOpen, setIsSidebarOpen] = useState(false);
  
  const [showSidebar, setShowSidebar] = React.useState(true);
  const [mainShow, setMainShow] = React.useState(true);

  function sideNavClicked() {
    isSidebarOpen ? closeNav() : openNav();
  }

  function openNav() {
    setIsSidebarOpen(true);
    setShowSidebar(true)
    document.getElementById('mySidebar').classList.add('sidebar- 
    show');
    setMainShow(true)
    document.getElementById('main').classList.add('main-show');
  }

  function closeNav() {
    setIsSidebarOpen(false);
    setShowSidebar(false)
    document.getElementById('mySidebar').classList.remove('sidebar- 
    show');
    setMainShow(false)
    document.getElementById('main').classList.remove('main-show');
  }

  function toggleMenuItem(element) {
    console.log('toggleMenuItem')
    setSidebarMenuToggle(false)
    
  document.getElementById(element.dataset.ulid).classList.toggle("ul- 
  show");
  }

}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1