H.Sdq
H.Sdq

Reputation: 857

How to update one component based on event handler of another component?

I have two components in my index.js file (Header and Sidebar) like below

import React from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.min.css';
import {
    BrowserRouter as Router,
    Route
} from "react-router-dom";
import './index.scss';
import './responsive.scss';
import Sidebar from './sidebar';
import Header from './header';
import Home from './home';
import Products from './products';
import Variant from './variant';
import Variety from './variety';
import * as serviceWorker from './serviceWorker';




ReactDOM.render(
    <Router>
        <div className="wrapper">
            <Header />
            <Sidebar />
            <div id="content">
                <Route exact path="/" component={Home} />
                <Route path="/products" component={Products} />
                <Route path="/variant" component={Variant} />
                <Route path="/variety" component={Variety} />
            </div>
        </div>
    </Router>
    , document.getElementById('root'));

serviceWorker.unregister();

I have a button in my Header component and I want to add an onClick event handler to it, so when clicked the sidebar in Sidebar component would be toggled. Now my problem is that I can not connect these two components. I have even tried to use what is suggested in this link How To Pass Events Between Components, but the problem is that the event targets the change of all the elements defined in the children's components. I have read something about the createPortal() but it was suggested to access the DOM outside the component and since I am trying to access a component from another one I'm not sure if I should be doing that. Your help is appreciated in advance.

Upvotes: 4

Views: 3917

Answers (4)

Root
Root

Reputation: 2361

First,simply about connecting these two components.The data transfer in React is suggested in pass from the father component to the child component.This is Lifting State Up.So normally, use callback to change the father component of header and pass the data back to sidebar.And now redux works well with react.So,simply set a state for Sidebar,and bind a function in onClick of Header.And add something in onClick.like this:

<header onClick = { this.expand.bind(this)}  />
<sidebar  sidebar = { this.state.sidebar} />

BTW,react provides us some ways to pass data.For example,context is used when component nesting is complex and it's hard to find the common father component.

Second,"the event targets the change of all the elements defined in the children's components".This problem is because of how the react works.You can use shouldComponentUpdate to avoid it.But not recommend here.

Third,about React Portal,it's added to React v16.It's used to render the child component outside the father component.This answer is good, if you want to know about it.How to use ReactDOM.createPortal() in React 16?. siderbar and header component are in the same levels.so I don't think it's nesscessary.

Upvotes: 1

Ankush Sharma
Ankush Sharma

Reputation: 677

As answered by everyone, these are some good solutions. But you have mentioned your constraints also. You can try below one also.

let showSidebar = true;

// Function to handle toggle
const handleClick = () => {
  showSidebar = !showSidebar
  renderApp()
}

// Make renderApp function
const renderApp = () => {
 ReactDOM.render(
    <Router>
        <div className="wrapper">
            <Header handleClick={handleClick}/> // call this function onClick inside your Header component 
            { showSidebar && <Sidebar /> }      // toggle the Sidebar
            <div id="content">
                <Route exact path="/" component={Home} />
                <Route path="/products" component={Products} />
                <Route path="/variant" component={Variant} />
                <Route path="/variety" component={Variety} />
            </div>
        </div>
    </Router>
    , document.getElementById('root'));
};
renderApp(); // Call renderApp for the first time

serviceWorker.unregister();

Upvotes: 1

Sagar
Sagar

Reputation: 1424

There are few ways.

  1. You can use Redux.
  2. Use React Context API https://reactjs.org/docs/context.html OR

You can do something like following

// IN MAIN FILE
state ={
    sidebarOpen : false
}
<header toggleSidebar = { this.toggleSidebar}  />
<sidebar  sidebarOpen = { this.state.sidebarOpen} /> 

toggleSidebar(){
    //UPDATE STATE
    this.setState({
        sidebarOpen : !(this.state.sidebarOpen)
    })
}

// IN HEADER

onButtonClick(){
    this.props.toggleSidebar()
}

IN SIDEBAR

componentWillReceiveProps(props){
    //LOGIC FOR UPDATING SIDEBAR YOU WILL RECIEVE UPDATED STATE HERE
}

Upvotes: 2

Roberto14
Roberto14

Reputation: 689

In order to connect components you should use a store to share the application state across all components. Something like Redux or similar would do it.

The main idea is that you change the state in the Header component, and Sidebar will be listening to this state and update itself if needed.

Upvotes: 2

Related Questions