Reactã®useContextããã¯ã«é¢ããå æ¬çãªã¬ã€ããã¹ã±ãŒã©ãã«ã§å¹ççãªã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããã®ãã³ã³ããã¹ãå©çšãã¿ãŒã³ãšé«åºŠãªããã©ãŒãã³ã¹æé©åæè¡ã解説ããŸãã
React useContext: ã³ã³ããã¹ãã®å©çšãšããã©ãŒãã³ã¹æé©åã®ãã¹ã¿ãŒ
Reactã®Context APIã¯ãã³ã³ããŒãã³ãããªãŒã®å
šã¬ãã«ãéããŠæç€ºçã«propsãæž¡ãããšãªããã³ã³ããŒãã³ãéã§ããŒã¿ãå
±æãã匷åãªæ¹æ³ãæäŸããŸããuseContextããã¯ã¯ã³ã³ããã¹ãå€ã®å©çšãç°¡çŽ åãã颿°ã³ã³ããŒãã³ãå
ã§å
±æããŒã¿ãžã®ã¢ã¯ã»ã¹ãšå©çšã容æã«ããŸããããããuseContextã®äžé©åãªäœ¿çšã¯ãç¹ã«å€§èŠæš¡ã§è€éãªã¢ããªã±ãŒã·ã§ã³ã«ãããŠãããã©ãŒãã³ã¹ã®ããã«ããã¯ã«ã€ãªããå¯èœæ§ããããŸãããã®ã¬ã€ãã§ã¯ãã³ã³ããã¹ãå©çšã®ãã¹ããã©ã¯ãã£ã¹ãæ¢æ±ããå¹ççã§ã¹ã±ãŒã©ãã«ãªReactã¢ããªã±ãŒã·ã§ã³ãä¿èšŒããããã®é«åºŠãªæé©åæè¡ãæäŸããŸãã
Reactã®Context APIãçè§£ãã
useContextã«é£ã³èŸŒãåã«ãContext APIã®ã³ã¢ã³ã³ã»ãããç°¡åã«åŸ©ç¿ããŸããããContext APIã¯äž»ã«3ã€ã®éšåããæ§æãããŸãïŒ
- Context: å
±æããŒã¿ã®ããã®ã³ã³ããã
React.createContext()ã䜿çšããŠã³ã³ããã¹ããäœæããŸãã - Provider: ã³ã³ããã¹ãã®å€ããã®åå«ã«æäŸããã³ã³ããŒãã³ãããããã€ããŒå ã«ã©ããããããã¹ãŠã®ã³ã³ããŒãã³ããã³ã³ããã¹ãå€ã«ã¢ã¯ã»ã¹ã§ããŸãã
- Consumer: ã³ã³ããã¹ãã®å€ã賌èªããã³ã³ããã¹ãã®å€ã倿Žããããã³ã«åã¬ã³ããªã³ã°ããã³ã³ããŒãã³ãã
useContextããã¯ã¯ã颿°ã³ã³ããŒãã³ãã§ã³ã³ããã¹ããå©çšããçŸä»£çãªæ¹æ³ã§ãã
useContextããã¯ã®ç޹ä»
useContextããã¯ã¯ã颿°ã³ã³ããŒãã³ããã³ã³ããã¹ãã賌èªã§ããããã«ããReactããã¯ã§ããã³ã³ããã¹ããªããžã§ã¯ãïŒReact.createContext()ã«ãã£ãŠè¿ãããå€ïŒãåãåãããã®ã³ã³ããã¹ãã®çŸåšã®å€ãè¿ããŸããã³ã³ããã¹ãã®å€ã倿Žããããšãã³ã³ããŒãã³ãã¯åã¬ã³ããªã³ã°ãããŸãã
以äžã«åºæ¬çãªäŸã瀺ããŸãïŒ
åºæ¬çãªäŸ
ããŒãã³ã³ããã¹ãããããšããŸãããïŒ
import React, { createContext, useContext, useState } from 'react';
const ThemeContext = createContext('light');
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prevTheme => prevTheme === 'light' ? 'dark' : 'light');
};
const value = {
theme,
toggleTheme,
};
return (
{children}
);
}
function ThemedComponent() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
Current Theme: {theme}
);
}
function App() {
return (
);
}
export default App;
ãã®äŸã§ã¯ïŒ
ThemeContextã¯React.createContext('light')ã䜿çšããŠäœæãããŸããããã©ã«ãå€ã¯'light'ã§ããThemeProviderã¯ãããŒãã®å€ãštoggleTheme颿°ããã®åã«æäŸããŸããThemedComponentã¯useContext(ThemeContext)ã䜿çšããŠãçŸåšã®ããŒããštoggleTheme颿°ã«ã¢ã¯ã»ã¹ããŸãã
äžè¬çãªèœãšã穎ãšããã©ãŒãã³ã¹ã®åé¡
useContextã¯ã³ã³ããã¹ãã®å©çšãç°¡çŽ åããŸãããæ³šæããŠäœ¿çšããªããšããã©ãŒãã³ã¹ã®åé¡ãåŒãèµ·ããå¯èœæ§ããããŸãã以äžã¯äžè¬çãªèœãšã穎ã§ãïŒ
- äžèŠãªåã¬ã³ããªã³ã°:
useContextã䜿çšããã³ã³ããŒãã³ãã¯ãã³ã³ããã¹ãã®å€ã倿Žããããã³ã«åã¬ã³ããªã³ã°ãããŸããããšãã³ã³ããŒãã³ããå®éã«å€æŽãããã³ã³ããã¹ãå€ã®ç¹å®ã®éšåã䜿çšããŠããªããŠãã§ããããã¯ãç¹ã«é »ç¹ã«æŽæ°ãããã³ã³ããã¹ãå€ãæã€å€§èŠæš¡ãªã¢ããªã±ãŒã·ã§ã³ã«ãããŠãäžèŠãªåã¬ã³ããªã³ã°ãšããã©ãŒãã³ã¹ã®ããã«ããã¯ã«ã€ãªããå¯èœæ§ããããŸãã - 倧ããªã³ã³ããã¹ãå€: ã³ã³ããã¹ãå€ã倧ããªãªããžã§ã¯ãã§ããå Žåããã®ãªããžã§ã¯ãå ã®ããããã®ããããã£ãžã®å€æŽãããã¹ãŠã®ã³ã³ã·ã¥ãŒããŒã³ã³ããŒãã³ãã®åã¬ã³ããªã³ã°ãåŒãèµ·ãããŸãã
- é »ç¹ãªæŽæ°: ã³ã³ããã¹ãå€ãé »ç¹ã«æŽæ°ããããšãã³ã³ããŒãã³ãããªãŒå šäœã§åã¬ã³ããªã³ã°ã®ã«ã¹ã±ãŒããçºçããããã©ãŒãã³ã¹ã«åœ±é¿ãäžããå¯èœæ§ããããŸãã
ããã©ãŒãã³ã¹æé©åæè¡
ãããã®ããã©ãŒãã³ã¹åé¡ã軜æžããããã«ã以äžã®æé©åæè¡ãæ€èšããŠãã ããïŒ
1. ã³ã³ããã¹ãã®åå²
é¢é£ãããã¹ãŠã®ããŒã¿ãåäžã®ã³ã³ããã¹ãã«é 眮ãã代ããã«ãã³ã³ããã¹ããããå°ãããããç²åºŠã®çްããã³ã³ããã¹ãã«åå²ããŸããããã«ãããããŒã¿ã®ç¹å®ã®éšåã倿Žããããšãã«åã¬ã³ããªã³ã°ãããã³ã³ããŒãã³ãã®æ°ãæžå°ããŸãã
äŸïŒ
ãŠãŒã¶ãŒã®ãããã£ãŒã«æ
å ±ãšãŠãŒã¶ãŒèšå®ã®äž¡æ¹ãå«ãåäžã®UserContextã®ä»£ããã«ãããããã«åå¥ã®ã³ã³ããã¹ããäœæããŸãïŒ
import React, { createContext, useContext, useState } from 'react';
const UserProfileContext = createContext(null);
const UserSettingsContext = createContext(null);
function UserProfileProvider({ children }) {
const [profile, setProfile] = useState({
name: 'John Doe',
email: 'john.doe@example.com',
});
const updateProfile = (newProfile) => {
setProfile(newProfile);
};
const value = {
profile,
updateProfile,
};
return (
{children}
);
}
function UserSettingsProvider({ children }) {
const [settings, setSettings] = useState({
notificationsEnabled: true,
theme: 'light',
});
const updateSettings = (newSettings) => {
setSettings(newSettings);
};
const value = {
settings,
updateSettings,
};
return (
{children}
);
}
function ProfileComponent() {
const { profile } = useContext(UserProfileContext);
return (
Name: {profile?.name}
Email: {profile?.email}
);
}
function SettingsComponent() {
const { settings } = useContext(UserSettingsContext);
return (
Notifications: {settings?.notificationsEnabled ? 'Enabled' : 'Disabled'}
Theme: {settings?.theme}
);
}
function App() {
return (
);
}
export default App;
ããã§ããŠãŒã¶ãŒãããã£ãŒã«ã®å€æŽã¯UserProfileContextãå©çšããã³ã³ããŒãã³ãã®ã¿ãåã¬ã³ããªã³ã°ãããŠãŒã¶ãŒèšå®ã®å€æŽã¯UserSettingsContextãå©çšããã³ã³ããŒãã³ãã®ã¿ãåã¬ã³ããªã³ã°ããŸãã
2. React.memoã«ããã¡ã¢å
ã³ã³ããã¹ããå©çšããã³ã³ããŒãã³ããReact.memoã§ã©ããããŸããReact.memoã¯ã颿°ã³ã³ããŒãã³ããã¡ã¢åããé«éã³ã³ããŒãã³ãã§ããã³ã³ããŒãã³ãã®propsã倿ŽãããŠããªãå Žåãåã¬ã³ããªã³ã°ãé²ããŸããã³ã³ããã¹ãã®åå²ãšçµã¿åãããããšã§ãäžèŠãªåã¬ã³ããªã³ã°ã倧å¹
ã«åæžã§ããŸãã
äŸïŒ
import React, { useContext } from 'react';
const MyContext = React.createContext(null);
const MyComponent = React.memo(function MyComponent() {
const { value } = useContext(MyContext);
console.log('MyComponent rendered');
return (
Value: {value}
);
});
export default MyComponent;
ãã®äŸã§ã¯ãMyComponentã¯MyContextã®valueã倿Žããããšãã«ã®ã¿åã¬ã³ããªã³ã°ãããŸãã
3. useMemoãšuseCallback
useMemoãšuseCallbackã䜿çšããŠãã³ã³ããã¹ãå€ãšããŠæž¡ãããå€ã颿°ãã¡ã¢åããŸããããã«ãããã³ã³ããã¹ãå€ã¯åºã«ãªãäŸåé¢ä¿ã倿Žããããšãã«ã®ã¿å€æŽãããããšãä¿èšŒãããã³ã³ã·ã¥ãŒããŒã³ã³ããŒãã³ãã®äžèŠãªåã¬ã³ããªã³ã°ã鲿¢ãããŸãã
äŸïŒ
import React, { createContext, useState, useMemo, useCallback, useContext } from 'react';
const MyContext = createContext(null);
function MyProvider({ children }) {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount(prevCount => prevCount + 1);
}, []);
const contextValue = useMemo(() => ({
count,
increment,
}), [count, increment]);
return (
{children}
);
}
function MyComponent() {
const { count, increment } = useContext(MyContext);
console.log('MyComponent rendered');
return (
Count: {count}
);
}
function App() {
return (
);
}
export default App;
ãã®äŸã§ã¯ïŒ
useCallbackã¯increment颿°ãã¡ã¢åãããã®äŸåé¢ä¿ã倿Žããããšãã«ã®ã¿å€æŽãããããšãä¿èšŒããŸãïŒãã®å ŽåãäŸåé¢ä¿ããªããããç¡æéã«ã¡ã¢åãããŸãïŒãuseMemoã¯ã³ã³ããã¹ãã®å€ãã¡ã¢åããcountãŸãã¯increment颿°ã倿Žããããšãã«ã®ã¿å€æŽãããããšãä¿èšŒããŸãã
4. ã»ã¬ã¯ã¿ãŒ
ã»ã¬ã¯ã¿ãŒãå®è£ ããŠãã³ã³ã·ã¥ãŒããŒã³ã³ããŒãã³ãå ã§ã³ã³ããã¹ãå€ããå¿ èŠãªããŒã¿ã®ã¿ãæœåºããŸããããã«ãããã³ã³ããŒãã³ããäŸåããç¹å®ã®ããŒã¿ã倿Žããããšãã«ã®ã¿åã¬ã³ããªã³ã°ãããããã«ããããšã§ãäžèŠãªåã¬ã³ããªã³ã°ã®å¯èœæ§ãæžãããŸãã
äŸïŒ
import React, { createContext, useContext } from 'react';
const MyContext = createContext(null);
const selectCount = (contextValue) => contextValue.count;
function MyComponent() {
const contextValue = useContext(MyContext);
const count = selectCount(contextValue);
console.log('MyComponent rendered');
return (
Count: {count}
);
}
export default MyComponent;
ãã®äŸã¯ç°¡ç¥åãããŠããŸãããå®éã®ã·ããªãªã§ã¯ãç¹ã«å€§ããªã³ã³ããã¹ãå€ãæ±ãå Žåãã»ã¬ã¯ã¿ãŒã¯ããè€éã§ããã©ãŒãã³ã¹ãé«ããªãå¯èœæ§ããããŸãã
5. äžå€ããŒã¿æ§é
äžå€ããŒã¿æ§é ã䜿çšãããšãã³ã³ããã¹ãå€ãžã®å€æŽãæ¢åã®ãªããžã§ã¯ãã倿Žãã代ããã«æ°ãããªããžã§ã¯ããäœæããããšãä¿èšŒãããŸããããã«ãããReactã倿Žãæ€åºããåã¬ã³ããªã³ã°ãæé©åãããããªããŸããImmutable.jsã®ãããªã©ã€ãã©ãªã¯ãäžå€ããŒã¿æ§é ã®ç®¡çã«åœ¹ç«ã¡ãŸãã
äŸïŒ
import React, { createContext, useState, useMemo, useContext } from 'react';
import { Map } from 'immutable';
const MyContext = createContext(Map());
function MyProvider({ children }) {
const [data, setData] = useState(Map({
count: 0,
name: 'Initial Name',
}));
const increment = () => {
setData(prevData => prevData.set('count', prevData.get('count') + 1));
};
const updateName = (newName) => {
setData(prevData => prevData.set('name', newName));
};
const contextValue = useMemo(() => ({
data,
increment,
updateName,
}), [data]);
return (
{children}
);
}
function MyComponent() {
const contextValue = useContext(MyContext);
const count = contextValue.get('count');
console.log('MyComponent rendered');
return (
Count: {count}
);
}
function App() {
return (
);
}
export default App;
ãã®äŸã§ã¯ãImmutable.jsãå©çšããŠã³ã³ããã¹ãããŒã¿ã管çããåæŽæ°ãæ°ããäžå€ã®Mapãäœæããããšãä¿èšŒããŸããããã«ãããReactãåã¬ã³ããªã³ã°ããã广çã«æé©åããã®ã«åœ¹ç«ã¡ãŸãã
å®äžçã®äŸãšãŠãŒã¹ã±ãŒã¹
Context APIãšuseContextã¯ãããŸããŸãªå®äžçã®ã·ããªãªã§åºã䜿çšãããŠããŸãïŒ
- ããŒã管ç: å ã®äŸã§ç€ºããããã«ãã¢ããªã±ãŒã·ã§ã³å šäœã§ããŒãïŒã©ã€ã/ããŒã¯ã¢ãŒãïŒã管çããŸãã
- èªèšŒ: ãŠãŒã¶ãŒã®èªèšŒç¶æ ãšãŠãŒã¶ãŒããŒã¿ãããããå¿ èŠãšããã³ã³ããŒãã³ãã«æäŸããŸããäŸãã°ãã°ããŒãã«ãªèªèšŒã³ã³ããã¹ãã¯ããŠãŒã¶ãŒã®ãã°ã€ã³ããã°ã¢ãŠããããã³ãŠãŒã¶ãŒãããã¡ã€ã«ããŒã¿ã管çããprop drillingãªãã§ã¢ããªã±ãŒã·ã§ã³å šäœããã¢ã¯ã»ã¹å¯èœã«ããŸãã
- èšèª/ãã±ãŒã«èšå®: åœéåïŒi18nïŒãšããŒã«ã©ã€ãŒãŒã·ã§ã³ïŒl10nïŒã®ããã«ãçŸåšã®èšèªããã±ãŒã«èšå®ãã¢ããªã±ãŒã·ã§ã³å šäœã§å ±æããŸããããã«ãããã³ã³ããŒãã³ãã¯ãŠãŒã¶ãŒã®å¥œã¿ã®èšèªã§ã³ã³ãã³ãã衚瀺ã§ããŸãã
- ã°ããŒãã«èšå®: APIãšã³ããã€ã³ããæ©èœãã©ã°ãªã©ã®ã°ããŒãã«ãªèšå®ãå ±æããŸããããã¯ãèšå®ã«åºã¥ããŠã¢ããªã±ãŒã·ã§ã³ã®åäœãåçã«èª¿æŽããããã«äœ¿çšã§ããŸãã
- ã·ã§ããã³ã°ã«ãŒã: Eã³ããŒã¹ã¢ããªã±ãŒã·ã§ã³å šäœã§ãã·ã§ããã³ã°ã«ãŒãã®ç¶æ ã管çããã«ãŒãã®ã¢ã€ãã ãæäœãžã®ã¢ã¯ã»ã¹ãã³ã³ããŒãã³ãã«æäŸããŸãã
äŸïŒåœéåïŒi18nïŒ
åœéåã®ããã«Context APIã䜿çšããç°¡åãªäŸã以äžã«ç€ºããŸãïŒ
import React, { createContext, useState, useContext, useMemo } from 'react';
const LanguageContext = createContext({
locale: 'en',
messages: {},
});
const translations = {
en: {
greeting: 'Hello',
description: 'Welcome to our website!',
},
fr: {
greeting: 'Bonjour',
description: 'Bienvenue sur notre site web !',
},
es: {
greeting: 'Hola',
description: '¡Bienvenido a nuestro sitio web!',
},
};
function LanguageProvider({ children }) {
const [locale, setLocale] = useState('en');
const setLanguage = (newLocale) => {
setLocale(newLocale);
};
const messages = useMemo(() => translations[locale] || translations['en'], [locale]);
const contextValue = useMemo(() => ({
locale,
messages,
setLanguage,
}), [locale, messages]);
return (
{children}
);
}
function Greeting() {
const { messages } = useContext(LanguageContext);
return (
{messages.greeting}
);
}
function Description() {
const { messages } = useContext(LanguageContext);
return (
{messages.description}
);
}
function LanguageSwitcher() {
const { setLanguage } = useContext(LanguageContext);
return (
);
}
function App() {
return (
);
}
export default App;
ãã®äŸã§ã¯ïŒ
LanguageContextã¯çŸåšã®ãã±ãŒã«ãšã¡ãã»ãŒãžãæäŸããŸããLanguageProviderã¯ãã±ãŒã«ã®ç¶æ ã管çããã³ã³ããã¹ãã®å€ãæäŸããŸããGreetingãšDescriptionã³ã³ããŒãã³ãã¯ãã³ã³ããã¹ãã䜿çšããŠç¿»èš³ãããããã¹ãã衚瀺ããŸããLanguageSwitcherã³ã³ããŒãã³ãã¯ããŠãŒã¶ãŒãèšèªã倿Žã§ããããã«ããŸãã
useContextã®ä»£æ¿æ¡
useContextã¯åŒ·åãªããŒã«ã§ããããã¹ãŠã®ç¶æ
管çã·ããªãªã«ãšã£ãŠåžžã«æåã®è§£æ±ºçãšã¯éããŸããã以äžã«æ€èšãã¹ãããã€ãã®ä»£æ¿æ¡ã瀺ããŸãïŒ
- Redux: JavaScriptã¢ããªã®ããã®äºæž¬å¯èœãªç¶æ ã³ã³ãããReduxã¯ãç¹ã«å€§èŠæš¡ãªã¢ããªã±ãŒã·ã§ã³ã«ãããŠãè€éãªã¢ããªã±ãŒã·ã§ã³ã®ç¶æ ã管çããããã®äžè¬çãªéžæè¢ã§ãã
- MobX: ã·ã³ãã«ã§ã¹ã±ãŒã©ãã«ãªç¶æ 管çãœãªã¥ãŒã·ã§ã³ãMobXã¯ã芳枬å¯èœãªããŒã¿ãšèªåçãªãªã¢ã¯ãã£ããã£ã䜿çšããŠç¶æ ã管çããŸãã
- Recoil: Reactã®ããã®ç¶æ 管çã©ã€ãã©ãªã§ãã¢ãã ãšã»ã¬ã¯ã¿ãŒã䜿çšããŠç¶æ ã管çããŸããRecoilã¯ãReduxãMobXãããç²åºŠãé«ãå¹ççã«ãªãããã«èšèšãããŠããŸãã
- Zustand: åçŽåãããfluxã®ååã䜿çšãããå°ãããé«éã§ãã¹ã±ãŒã©ãã«ãªãã¢ããŒã³ã®ç¶æ 管çãœãªã¥ãŒã·ã§ã³ã
- Jotai: ã¢ãããã¯ã¢ãã«ã䜿çšãããReactã®ããã®ããªããã£ãã§æè»ãªç¶æ 管çã
- Prop Drilling: ã³ã³ããŒãã³ãããªãŒãæµ ãããåçŽãªã±ãŒã¹ã§ã¯ãprop drillingãå®è¡å¯èœãªéžæè¢ãããããŸãããããã¯ãã³ã³ããŒãã³ãããªãŒã®è€æ°ã®ã¬ãã«ãéããŠpropsãæž¡ãããšãå«ã¿ãŸãã
ç¶æ 管çãœãªã¥ãŒã·ã§ã³ã®éžæã¯ãã¢ããªã±ãŒã·ã§ã³ã®ç¹å®ã®ããŒãºã«äŸåããŸããæ±ºå®ãäžãéã«ã¯ãã¢ããªã±ãŒã·ã§ã³ã®è€éããããŒã ã®èŠæš¡ãããã³ããã©ãŒãã³ã¹èŠä»¶ãèæ ®ããŠãã ããã
çµè«
Reactã®useContextããã¯ã¯ãã³ã³ããŒãã³ãéã§ããŒã¿ãå
±æããããã®äŸ¿å©ã§å¹ççãªæ¹æ³ãæäŸããŸããæœåšçãªããã©ãŒãã³ã¹ã®èœãšã穎ãçè§£ãããã®ã¬ã€ãã§æŠèª¬ããæé©åæè¡ãé©çšããããšã§ãuseContextã®åãæŽ»çšããŠãã¹ã±ãŒã©ãã«ã§ããã©ãŒãã³ã¹ã®é«ãReactã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã§ããŸããé©åãªå Žåã«ã¯ã³ã³ããã¹ããåå²ããã³ã³ããŒãã³ããReact.memoã§ã¡ã¢åããã³ã³ããã¹ãå€ã«useMemoãšuseCallbackãå©çšããã»ã¬ã¯ã¿ãŒãå®è£
ããäžèŠãªåã¬ã³ããªã³ã°ãæå°éã«æããŠã¢ããªã±ãŒã·ã§ã³ã®ããã©ãŒãã³ã¹ãæé©åããããã«äžå€ããŒã¿æ§é ã®äœ¿çšãæ€èšããããšãå¿ããªãã§ãã ããã
ã³ã³ããã¹ãã®å©çšã«é¢é£ããããã«ããã¯ãç¹å®ããŠå¯ŸåŠããããã«ãåžžã«ã¢ããªã±ãŒã·ã§ã³ã®ããã©ãŒãã³ã¹ããããã¡ã€ãªã³ã°ããŠãã ããããããã®ãã¹ããã©ã¯ãã£ã¹ã«åŸãããšã§ãuseContextã®äœ¿çšãã¹ã ãŒãºã§å¹ççãªãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã«è²¢ç®ããããšãä¿èšŒã§ããŸãã