How to Pass Data Between Sibling Components in React
To pass data between sibling components in React, lift the shared state up to their common parent component using
useState. The parent holds the data and passes it down as props to each sibling, enabling communication through the parent.Syntax
Use useState in the parent component to hold the shared data. Pass the data and a function to update it as props to sibling components. Siblings call the update function to change the data, which flows back down as updated props.
This pattern is called "lifting state up".
jsx
function Parent() { const [sharedData, setSharedData] = React.useState(''); return ( <> <SiblingA data={sharedData} setData={setSharedData} /> <SiblingB data={sharedData} /> </> ); } function SiblingA({ data, setData }) { return <input value={data} onChange={e => setData(e.target.value)} />; } function SiblingB({ data }) { return <p>Data from sibling: {data}</p>; }
Example
This example shows two sibling components: one with an input box to update shared data, and the other displaying that data. The parent holds the state and passes it down.
jsx
import React, { useState } from 'react'; import ReactDOM from 'react-dom/client'; function Parent() { const [sharedData, setSharedData] = useState('Hello'); return ( <div> <h2>Sibling Components Sharing Data</h2> <SiblingA data={sharedData} setData={setSharedData} /> <SiblingB data={sharedData} /> </div> ); } function SiblingA({ data, setData }) { return ( <div> <label htmlFor="inputA">Type here: </label> <input id="inputA" value={data} onChange={e => setData(e.target.value)} aria-label="Input to update shared data" /> </div> ); } function SiblingB({ data }) { return <p>Sibling B shows: <strong>{data}</strong></p>; } const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<Parent />);
Output
Sibling Components Sharing Data
Type here: [Hello]
Sibling B shows: Hello
Common Pitfalls
- Not lifting state up: Trying to share state directly between siblings without a common parent causes data mismatch.
- Updating props directly: Props are read-only; siblings must use parent's setter function to update shared data.
- Overcomplicating with context or external stores: For simple sibling communication, lifting state up is easier and clearer.
jsx
/* Wrong: siblings try to update each other's state directly (won't work) */ function SiblingA({ setSiblingBData }) { return <button onClick={() => setSiblingBData('New Data')}>Update B</button>; } function SiblingB({ data }) { return <p>{data}</p>; } /* Right: parent holds state and passes setter down */ function Parent() { const [data, setData] = React.useState(''); return ( <> <SiblingA setSiblingBData={setData} /> <SiblingB data={data} /> </> ); }
Quick Reference
- Lift shared state to the closest common parent.
- Pass state and setter as props to siblings.
- Siblings update state via parent's setter function.
- Props flow down, events flow up.
Key Takeaways
Lift shared state to the common parent component to enable sibling communication.
Pass state and setter functions as props to sibling components.
Siblings update shared data by calling the parent's setter function.
Never try to update props directly; props are read-only.
For simple cases, lifting state up is clearer than using context or external stores.