How to share state between child component (siblings) in ReactJS?

You have different approaches to address this situation.

  • Keep the state in the top component and pass it to children through props
  • Use a state container to keep and share your application state among components (e.g. https://redux.js.org/)
  • Use the new React Context feature. Context provides a way to pass data through the component tree without having to pass props down manually at every level.

That's the exact reason why "React Hooks" have been developed (and hyped by the community ), but don't use them yet in production, they are still in early development (alpha) and their specification/implementation might be changed!

You problem can be solved using the awesome “React Context“ API which allows to pass data to components no matter how deep they are nested in the tree. To get to know to context read the extensive documentation linked above. I'll only explain a small and quick example here:

  1. Create a context component and export the consumer

App.jsx

import React from "react";

// The initial value can be anything, e.g. primitives, object, function,
// components, whatever...
// Note that this is not required, but prevebents errors and can be used as
// fallback value.
const MyContext = React.createContext("anything");

// This component is the so called "consumer" that'll provide the values passed
// to the context component. This is not necessary, but simplifies the usage and
// hides the underlying implementation.
const MyContextConsumer = MyContext.Consumer;

const someData = { title: "Hello World" };

const App = ({ children }) => (
  <MyContext.Provider value={someData}>{children}</MyContext.Provider>
);

export { MyContextConsumer };
export default App;
  1. Import the created consumer in any component and use the provided value

AnotherComponent.jsx

import React from "react";
import { MyContextConsumer } from "./App";

const AnotherComponent = () => (
  <div>
    <MyContextConsumer>{({ title }) => <h1>{title}</h1>}</MyContextConsumer>
  </div>
);

export default AnotherComponent;
  1. Render the app with both context components
import React from "react";
import ReactDOM from "react-dom";

import App from "./App";
import AnotherComponent from "./AnotherComponent";

const Root = () => (
  <App>
    <AnotherComponent />
  </App>
);

const rootElement = document.getElementById("root");
ReactDOM.render(<Root />, rootElement);

The component will render a level 1 heading with the "Hello World" text.

Edit stackoverflow-53648661-how-to-share-state-between-child-component-siblings-in-reactjs


How to pass state (such as isDropdownOpened) from Header to Navigation and AnotherComponent, please ?

You hold the state in an ancestor of Header and pass that state to Haeader, Navigation, and AnotherComponent as props. See State and Lifecycle and Lifting State Up in the documentation.

Example:

const Header = props => (
    <div>
        <span>Header: </span>
        {props.isDropdownOpened ? "Open" : "Closed"}
    </div>
);

const Navigation = props => (
    <div>
        <span>Navigation: </span>
        {props.isDropdownOpened ? "Open" : "Closed"}
    </div>
);

const AnotherComponent = props => (
    <div>
        <span>AnotherComponent: </span>
        {props.isDropdownOpened ? "Open" : "Closed"}
    </div>
);

class Wrapper extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
          isDropdownOpened: false
        };
    }
    componentDidMount() {
        setInterval(() => {
            this.setState(({isDropdownOpened}) => {
                isDropdownOpened = !isDropdownOpened;
                return {isDropdownOpened};
            });
        }, 1200);
    }
    render() {
        const {isDropdownOpened} = this.state;
        return (
            <div>
              <Header isDropdownOpened={isDropdownOpened} />
              <Navigation isDropdownOpened={isDropdownOpened} />
              <div>
                 <div>
                     <div>
                          <AnotherComponent isDropdownOpened={isDropdownOpened} />
                     </div>
                 </div>
              </div>
          </div>
        );
    }
}

ReactDOM.render(
    <Wrapper />,
    document.getElementById("root")
);
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>


There are some other options, which Arnaud usefully provides in his answer.