Passing data between React components is a fundamental part of building React applications. Here are several common methods to achieve this:
1. Props
Props are the primary way to pass data from a parent component to a child component.
// ParentComponent.js
import React from 'react';
import ChildComponent from './ChildComponent';
const ParentComponent = () => {
const data = "Hello from Parent!";
return <ChildComponent message={data} />;
};
export default ParentComponent;
// ChildComponent.js
import React from 'react';
const ChildComponent = ({ message }) => {
return <div>{message}</div>;
};
export default ChildComponent;
2. State Lifting
When two sibling components need to share data, you can lift the state up to their common ancestor and pass it down as props.
// ParentComponent.js
import React, { useState } from 'react';
import Sibling1 from './Sibling1';
import Sibling2 from './Sibling2';
const ParentComponent = () => {
const [sharedData, setSharedData] = useState("Shared Data");
return (
<div>
<Sibling1 data={sharedData} />
<Sibling2 setData={setSharedData} />
</div>
);
};
export default ParentComponent;
// Sibling1.js
import React from 'react';
const Sibling1 = ({ data }) => {
return <div>{data}</div>;
};
export default Sibling1;
// Sibling2.js
import React from 'react';
const Sibling2 = ({ setData }) => {
return <button onClick={() => setData("New Data")}>Update Data</button>;
};
export default Sibling2;
3. Context API
The Context API allows you to share data globally across your component tree without having to pass props down manually at every level.
// MyContext.js
import React, { createContext, useState } from 'react';
export const MyContext = createContext();
export const MyProvider = ({ children }) => {
const [data, setData] = useState("Context Data");
return (
<MyContext.Provider value={{ data, setData }}>
{children}
</MyContext.Provider>
);
};
// ParentComponent.js
import React from 'react';
import { MyProvider } from './MyContext';
import ChildComponent from './ChildComponent';
const ParentComponent = () => {
return (
<MyProvider>
<ChildComponent />
</MyProvider>
);
};
export default ParentComponent;
// ChildComponent.js
import React, { useContext } from 'react';
import { MyContext } from './MyContext';
const ChildComponent = () => {
const { data, setData } = useContext(MyContext);
return (
<div>
<p>{data}</p>
<button onClick={() => setData("Updated Context Data")}>Update Data</button>
</div>
);
};
export default ChildComponent;
4. Custom Hooks
Custom hooks can encapsulate shared logic and data and be used across different components.
// useSharedData.js
import { useState } from 'react';
const useSharedData = () => {
const [data, setData] = useState("Shared Data via Hook");
return { data, setData };
};
export default useSharedData;
// ParentComponent.js
import React from 'react';
import useSharedData from './useSharedData';
import ChildComponent from './ChildComponent';
const ParentComponent = () => {
const sharedData = useSharedData();
return <ChildComponent sharedData={sharedData} />;
};
export default ParentComponent;
// ChildComponent.js
import React from 'react';
const ChildComponent = ({ sharedData }) => {
const { data, setData } = sharedData;
return (
<div>
<p>{data}</p>
<button onClick={() => setData("Updated Data via Hook")}>Update Data</button>
</div>
);
};
export default ChildComponent;
5. Third-Party State Management Libraries
Libraries like Redux or MobX provide robust solutions for managing global state across an application.
Redux Example
// store.js
import { createStore } from 'redux';
const initialState = { data: "Redux Data" };
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'UPDATE_DATA':
return { ...state, data: action.payload };
default:
return state;
}
};
export const store = createStore(reducer);
// ParentComponent.js
import React from 'react';
import { Provider } from 'react-redux';
import { store } from './store';
import ChildComponent from './ChildComponent';
const ParentComponent = () => {
return (
<Provider store={store}>
<ChildComponent />
</Provider>
);
};
export default ParentComponent;
// ChildComponent.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
const ChildComponent = () => {
const data = useSelector((state) => state.data);
const dispatch = useDispatch();
return (
<div>
<p>{data}</p>
<button onClick={() => dispatch({ type: 'UPDATE_DATA', payload: "Updated Redux Data" })}>Update Data</button>
</div>
);
};
export default ChildComponent;
These methods provide flexibility in how you manage and share data across your React components, depending on the complexity and requirements of your application.