In React, there are several ways to share data between components, depending on the relationship between them and the complexity of the application. Here are the most common methods:
1. Props (Parent to Child) – One-way Data Flow
Props (short for properties) are used to pass data from a parent component to a child component.
Example:
javascriptCopyEditfunction Parent() {
const message = 'Hello from Parent!';
return <Child text={message} />;
}
function Child({ text }) {
return <p>{text}</p>;
}
✅ When to Use:
- When data needs to flow from a parent to a child.
- Props are read-only in the child.
2. Lifting State Up (Child to Parent)
When a child component needs to pass data to a parent, you lift the state up:
- The state is managed in the parent.
- A function is passed as a prop to the child, and the child calls this function to update the parent’s state.
Example:
javascriptCopyEditimport { useState } from 'react';
function Parent() {
const [data, setData] = useState('');
const handleDataChange = (value) => {
setData(value);
};
return (
<div>
<Child onDataChange={handleDataChange} />
<p>Data from Child: {data}</p>
</div>
);
}
function Child({ onDataChange }) {
return <input type="text" onChange={(e) => onDataChange(e.target.value)} />;
}
✅ When to Use:
- When a child component’s data affects the parent component’s state.
3. Context API (Global State Sharing)
Context API is used to share data globally across the entire component tree without prop drilling (passing props through multiple components).
Steps to Use Context:
- Create a Context:javascriptCopyEdit
import { createContext } from 'react'; export const UserContext = createContext();
- Provide Context Value:javascriptCopyEdit
function App() { const user = { name: 'John Doe', age: 30 }; return ( <UserContext.Provider value={user}> <Child /> </UserContext.Provider> ); }
- Consume Context:javascriptCopyEdit
import { useContext } from 'react'; import { UserContext } from './UserContext'; function Child() { const user = useContext(UserContext); return <p>User: {user.name}, Age: {user.age}</p>; }
✅ When to Use:
- When multiple components need access to the same data (e.g., user authentication, themes).
- Avoids prop drilling.
4. Props Drilling (Avoid When Possible)
Props drilling is passing data down through many levels of nested components via props.
Example:
javascriptCopyEditfunction App() {
const user = 'John';
return <Parent user={user} />;
}
function Parent({ user }) {
return <Child user={user} />;
}
function Child({ user }) {
return <p>{user}</p>;
}
Better Approach: Use Context API instead of props drilling.
5. State Management Libraries (Redux, Zustand, etc.)
For large-scale applications, you may need external state management libraries:
- Redux – Centralized global state.
- Zustand – Simpler, minimal global state management.
- Recoil, MobX, Jotai – Other state libraries.
✅ When to Use:
- When state needs to be shared across many unrelated components.
- For complex state logic and scalability.
Comparison Summary:
Method | Use Case | Complexity |
---|---|---|
Props | Parent → Child (One-way data flow) | Low |
Lifting State Up | Child → Parent (through callbacks) | Low |
Context API | Global state (Avoid prop drilling) | Medium |
State Libraries (Redux, Zustand, etc.) | Complex state across unrelated components | High |
Best Practices:
✅ Props and Lifting State Up for simple, localized data sharing.
✅ Context API for app-wide data like themes, authentication.
✅ Redux/Zustand for large, complex applications.