useContext Hook
useContext Hook — Գլոբալ state-ի կառավարում React-ում
React-ում տվյալները սովորաբար փոխանցվում են ծնողից երեխա՝ props-երի միջոցով։ Սակայն երբ տվյալը պետք է հասանելի լինի շատ կոմպոնենտներում՝ այդ մեթոդը դառնում է ոչ արդյունավետ։ Այդ խնդիրն է լուծում Context API-ն, որը թույլ է տալիս ստեղծել գլոբալ state, որը հասանելի է ցանկացած կոմպոնենտում՝ առանց prop drilling-ի։
Context-ը React-ի ներդրված համակարգ է, որը թույլ է տալիս կիսվել տվյալներով ամբողջ հավելվածի տարբեր մասերի միջև։ Այն բաղկացած է երեք հիմնական մասից․
Սա դասական օրինակ է՝ երբ ունենք երկու թեմա՝ լույս և մուգ։ Մենք ուզում ենք, որ այդ թեման հասանելի լինի ամբողջ հավելվածում՝ առանց յուրաքանչյուր կոմպոնենտին props տալու։
// ThemeContext.js
import React, { createContext, useState } from 'react';
export const ThemeContext = createContext();
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prev => (prev === 'light' ? 'dark' : 'light'));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
Այստեղ մենք ստեղծեցինք context, որը տրամադրում է երկու արժեք՝ theme և toggleTheme։
// App.js
import React from 'react';
import { ThemeProvider } from './ThemeContext';
import Page from './Page';
export default function App() {
return (
<ThemeProvider>
<Page />
</ThemeProvider>
);
}
// Page.js
import React, { useContext } from 'react';
import { ThemeContext } from './ThemeContext';
export default function Page() {
const { theme, toggleTheme } = useContext(ThemeContext);
const styles = {
background: theme === 'light' ? '#fff' : '#333',
color: theme === 'light' ? '#000' : '#fff',
padding: '20px',
borderRadius: '8px',
};
return (
<div style={styles}>
<h2>Ընթացիկ թեմա՝ {theme}</h2>
<button onClick={toggleTheme}>Փոխել թեման</button>
</div>
);
}
Այժմ, երբ սեղմում ես կոճակը, ամբողջ հավելվածը ավտոմատ փոխում է իր թեման՝ առանց props փոխանցելու։ Այսպիսի մոտեցումը շատ օգտակար է նաև user auth, language, settings և notification համակարգերի համար։
React-ը հիշում է՝ որ Provider-ի տակ է տվյալ կոմպոնենտը render արվել։
Երբ Provider-ի value-ն փոխվում է, բոլոր այն կոմպոնենտները, որոնք օգտագործում են useContext, ավտոմատ rerender են լինում։
Սա հիշեցնում է Redux-ի կամ Zustand-ի նման գլոբալ state։
Կարող ես միաժամանակ օգտագործել մի քանի context, օրինակ՝ user authentication-ի և theme-ի համար։
// UserContext.js
import React, { createContext, useState } from 'react';
export const UserContext = createContext();
export function UserProvider({ children }) {
const [user, setUser] = useState(null);
const login = (name) => setUser({ name });
const logout = () => setUser(null);
return (
<UserContext.Provider value={{ user, login, logout }}>
{children}
</UserContext.Provider>
);
}
// App.js
import { ThemeProvider } from './ThemeContext';
import { UserProvider } from './UserContext';
import HomePage from './HomePage';
export default function App() {
return (
<ThemeProvider>
<UserProvider>
<HomePage />
</UserProvider>
</ThemeProvider>
);
}
// HomePage.js
import React, { useContext } from 'react';
import { ThemeContext } from './ThemeContext';
import { UserContext } from './UserContext';
export default function HomePage() {
const { theme, toggleTheme } = useContext(ThemeContext);
const { user, login, logout } = useContext(UserContext);
return (
<div>
<h2>Թեմա՝ {theme}</h2>
<button onClick={toggleTheme}>Փոխել թեման</button>
<hr />
{user ? (
<div>
<p>Բարև, {user.name}!</p>
<button onClick={logout}>Ելք</button>
</div>
) : (
<button onClick={() => login('Արամ')}>Մուտք</button>
)}
</div>
);
}
Եթե Provider-ի value-ն ստեղծվում է նոր օբյեկտ կամ ֆունկցիա յուրաքանչյուր render-ի ժամանակ,
բոլոր ներքին կոմպոնենտները նույնպես rerender կդառնան։
Խուսափելու համար՝ օգտագործիր useMemo կամ useCallback։
const value = useMemo(() => ({ theme, toggleTheme }), [theme]);
<ThemeContext.Provider value={value}>...
Գրիր կոմպոնենտային համակարգ, որը․