Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make clicking a menu button toggle show/hide of a menu sidebar component

Tags:

reactjs

I have this three component app.js, header.js and menu.js. I'm trying to code when you click on menu button which is in header component it toggles (show/hide) menu component (menu-sidebar). Is it possible to make such communication in react with two components without jQuery? I tried with this tutorial but didn't succeed https://www.codementor.io/chrisharrington/how-to-build-a-sliding-menu-using-react-js-and-less-css-du107mpij

app.js:

import React, { Component } from 'react';

// components
import Header from './components/header';
import Menu from './components/menu';

class App extends Component {
  render() {
    return (
      <div className="App">
        <Header />
        <Menu />  
      </div>
    );
  }
}

export default App;

header.js:

import React, { Component } from 'react';

class Header extends Component {
    render() {
        return (
            <header id="header">
                <h1><a href="/">Lorem</a></h1>
                <nav className="links">
                    <ul>
                        <li><a href="/">Lorem</a></li>
                        <li><a href="/">Ipsum</a></li>
                        <li><a href="/">Feugiat</a></li>
                        <li><a href="/">Tempus</a></li>
                        <li><a href="/">Adipiscing</a></li>
                    </ul>
                </nav>
                <nav className="main">
                    <ul>
                        <li className="search">
                            search
                        </li>
                        <li className="menu">
                            <a className="fa-bars" href="#menu">Menu</a>
                        </li>
                    </ul>
                </nav>
            </header>
        );
    }
}

export default Header;

menu.js:

import React, { Component } from 'react';

class Menu extends Component {
    render() {
        return (

    <section id="menu">
        <section>
            <form className="search" method="get" action="#">
                <input type="text" name="query" placeholder="Search" />
            </form>
        </section>
        {/* Links */}
        <section>
            <ul className="links">
                <li>
                    <a href="/">
                        <h3>Lorem ipsum</h3>
                        <p>Feugiat tempus veroeros dolor</p>
                    </a>
                </li>
                <li>
                    <a href="/">
                        <h3>Dolor sit amet</h3>
                        <p>Sed vitae justo condimentum</p>
                    </a>
                </li>
                <li>
                    <a href="/">
                        <h3>Feugiat veroeros</h3>
                        <p>Phasellus sed ultricies mi congue</p>
                    </a>
                </li>
                <li>
                    <a href="/">
                        <h3>Etiam sed consequat</h3>
                        <p>Porta lectus amet ultricies</p>
                    </a>
                </li>
            </ul>
        </section>
    </section>
        );
    }
}

export default Menu;
like image 259
Aleksandar Batin Avatar asked Oct 31 '17 09:10

Aleksandar Batin


1 Answers

What you want to achieve is a very common pattern in React. Which is good because you can easily achieve it. You need to pass information from one component to another. So you need some kind of state management. There are different approaches. Your use case is easy, so no need for over-engineering. What you can do:

Pass props and functions (suitable here)

React uses a unidrectional data flow. It always goes from parent components to the children and by default children can not alter this data (called props). You this like so: <Header myvariable='something'/>.

You might wonder: If I only can pass info DOWN how to pass it UP, in your case from menu to header when the button is clicked. The react pattern to solve this is not to change data directly but rather pass a function from the parent component to the child that changes the data and distributes the new value. Let me show you. This is your app:

- APP
-- Header
-- Menu

Your parent is APP, children are header and menu. To get data from Menu to header you need to enable APP to manage this data by doing the following:

  1. define the variable you need as state of app, e.g. showMenu (in example below I used the constructor to set a default value).
  2. pass toggleMenu to the menu component with <Menu showMenu={showMenu}/>
  3. Pass a function to alter showMenu from App to Header to enable header to alter the toggle (or rather: call the function in App that actually alters it).

Here is a working sandbox: https://codesandbox.io/s/l4n7p435kz

Simplified for your case:

App
class App extends Component {

constructor(props){
    super(props);
    this.state = { showMenu: true };
}

toggleMenu() {
    this.state.showMenu = !this.state.showMenu //Flips true/false
}

render() {
    return (
      <div className="App">
        <Header toggleFunction={this.toggleMenu}/>
        <Menu showMenu={this.state.showMenu}/>  
      </div>
    );
  }
}

Now you can use the function toggleMenu in your header like this:

<button onClick={this.props.toggleMenu()}/>

And the variable in your Menu component:

return (
    {this.props.showMenu && <div> ... your menu code </div>} 
)

There might be a few kinks you need to consider to make this work but if you struggle just comment on it.

Use React-Redux (overkill)

If you have A LOT of communication between components and need to pass them down long ways things get unwieldy. For these kind of cases you can use redux. It basically capsules all state changes and remembers them in a separate storage. You could compare it to a state-database that has some standard interfaces. Feel free to read up on redux, but for your case something far simpler will do.

like image 111
Gegenwind Avatar answered Oct 18 '22 03:10

Gegenwind