React Context Providerã®ããã©ãŒãã³ã¹ãæé©åãããããã³ã³ããã¹ãå€ãã¡ã¢åããæ¹æ³ã解説ãäžèŠãªåã¬ã³ããªã³ã°ãé²ããã¢ããªã®å¹çãé«ããŠã¹ã ãŒãºãªUXãå®çŸããŸãã
React Context Providerã®ã¡ã¢åïŒContextã®å€ã®æŽæ°ãæé©åãã
Reactã®Context APIã¯ãããããã¹ã®ãã±ããªã¬ãŒãå¿ èŠãšããã«ã³ã³ããŒãã³ãéã§ããŒã¿ãå ±æããããã®åŒ·åãªã¡ã«ããºã ãæäŸããŸããããããæ³šæããŠäœ¿çšããªããšãã³ã³ããã¹ãå€ã®é »ç¹ãªæŽæ°ãã¢ããªã±ãŒã·ã§ã³å šäœã§äžèŠãªåã¬ã³ããªã³ã°ãåŒãèµ·ãããããã©ãŒãã³ã¹ã®ããã«ããã¯ã«ã€ãªããå¯èœæ§ããããŸãããã®èšäºã§ã¯ãã¡ã¢åãéããŠContext Providerã®ããã©ãŒãã³ã¹ãæé©åããå¹ççãªæŽæ°ãšããã¹ã ãŒãºãªãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã確ä¿ããããã®ãã¯ããã¯ãæ¢ããŸãã
React Context APIãšåã¬ã³ããªã³ã°ã®çè§£
React Context APIã¯ãäž»ã«3ã€ã®éšåããæ§æãããŸãïŒ
- Context:
React.createContext()ã䜿çšããŠäœæãããŸããããŒã¿ãšæŽæ°é¢æ°ãä¿æããŸãã - Provider: ã³ã³ããŒãã³ãããªãŒã®äžéšãã©ãããããã®åã«ã³ã³ããã¹ãå€ãæäŸããã³ã³ããŒãã³ãã§ããProviderã®ã¹ã³ãŒãå ã«ããã©ã®ã³ã³ããŒãã³ããã³ã³ããã¹ãã«ã¢ã¯ã»ã¹ã§ããŸãã
- Consumer: ã³ã³ããã¹ãã®å€æŽã賌èªããã³ã³ããã¹ãå€ãæŽæ°ããããšåã¬ã³ããªã³ã°ããã³ã³ããŒãã³ãã§ãïŒå€ãã®å Žåã
useContextããã¯ãä»ããŠæé»çã«äœ¿çšãããŸãïŒã
ããã©ã«ãã§ã¯ãContext Providerã®å€ã倿Žããããšããã®ã³ã³ããã¹ãã䜿çšãããã¹ãŠã®ã³ã³ããŒãã³ãããå®éã«å€æŽãããããŒã¿ã䜿çšããŠãããã©ããã«é¢ãããåã¬ã³ããªã³ã°ãããŸããããã¯ãç¹ã«ã³ã³ããã¹ãå€ãProviderã³ã³ããŒãã³ãã®ã¬ã³ããªã³ã°ããšã«åäœæããããªããžã§ã¯ãã颿°ã§ããå Žåã«åé¡ãšãªãå¯èœæ§ããããŸãããªããžã§ã¯ãå ã®åºã«ãªãããŒã¿ã倿ŽãããŠããªããŠããåç §ã®å€æŽãåã¬ã³ããªã³ã°ãåŒãèµ·ãããŸãã
åé¡ç¹ïŒäžèŠãªåã¬ã³ããªã³ã°
ããŒãã³ã³ããã¹ãã®ç°¡åãªäŸãèããŠã¿ãŸãããïŒ
// ThemeContext.js
import React, { createContext, useState } from 'react';
export const ThemeContext = createContext();
export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prevTheme => prevTheme === 'light' ? 'dark' : 'light');
};
const value = {
theme,
toggleTheme,
};
return (
{children}
);
};
// App.js
import React, { useContext } from 'react';
import { ThemeContext } from './ThemeContext';
function App() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
);
}
function SomeOtherComponent() {
// This component might not even use the theme directly
return Some other content
;
}
export default App;
ãã®äŸã§ã¯ãSomeOtherComponentãthemeãtoggleThemeãçŽæ¥äœ¿çšããŠããªããŠããThemeProviderã®åã§ãããã³ã³ããã¹ãã䜿çšããŠãããããããŒããåãæ¿ãããã³ã«åã¬ã³ããªã³ã°ãããŸãã
解決çïŒã¡ã¢åã®æŽ»çš
ã¡ã¢åã¯ãé«ã³ã¹ããªé¢æ°åŒã³åºãã®çµæããã£ãã·ã¥ããåãå ¥åãå床çºçããå Žåã«ãã£ãã·ã¥ãããçµæãè¿ãããšã§ããã©ãŒãã³ã¹ãæé©åããææ³ã§ããReact Contextã®æèã§ã¯ãã¡ã¢åã䜿çšããŠãåºã«ãªãããŒã¿ãå®éã«å€æŽããããšãã«ã®ã¿ã³ã³ããã¹ãå€ã倿Žãããããã«ããããšã§ãäžèŠãªåã¬ã³ããªã³ã°ãé²ãããšãã§ããŸãã
1. useMemoã«ããã³ã³ããã¹ãå€ã®ã¡ã¢å
useMemoããã¯ã¯ãã³ã³ããã¹ãå€ãã¡ã¢åããã®ã«æé©ã§ããäŸåé¢ä¿ã®ããããã倿Žããããšãã«ã®ã¿å€æŽãããå€ãäœæã§ããŸãã
// ThemeContext.js (Optimized with useMemo)
import React, { createContext, useState, useMemo } from 'react';
export const ThemeContext = createContext();
export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prevTheme => prevTheme === 'light' ? 'dark' : 'light');
};
const value = useMemo(() => ({
theme,
toggleTheme,
}), [theme, toggleTheme]); // Dependencies: theme and toggleTheme
return (
{children}
);
};
ã³ã³ããã¹ãå€ãuseMemoã§ã©ããããããšã§ãvalueãªããžã§ã¯ãã¯themeãŸãã¯toggleTheme颿°ã®ããããã倿Žããããšãã«ã®ã¿åäœæãããããã«ãªããŸããããããããã¯æ°ããªæœåšçãªåé¡ãåŒãèµ·ãããŸããtoggleTheme颿°ãThemeProviderã³ã³ããŒãã³ãã®ã¬ã³ããªã³ã°ããšã«åäœæããããããuseMemoãåå®è¡ãããã³ã³ããã¹ãå€ãäžå¿
èŠã«å€æŽãããŠããŸããŸãã
2. useCallbackã«ãã颿°ã®ã¡ã¢å
toggleTheme颿°ãã¬ã³ããªã³ã°ããšã«åäœæãããåé¡ã解決ããããã«ãuseCallbackããã¯ã䜿çšã§ããŸããuseCallbackã¯é¢æ°ãã¡ã¢åãããã®äŸåé¢ä¿ã®ããããã倿Žããããšãã«ã®ã¿é¢æ°ã倿Žãããããã«ããŸãã
// ThemeContext.js (Optimized with useMemo and useCallback)
import React, { createContext, useState, useMemo, useCallback } from 'react';
export const ThemeContext = createContext();
export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = useCallback(() => {
setTheme(prevTheme => prevTheme === 'light' ? 'dark' : 'light');
}, []); // No dependencies: The function doesn't rely on any values from the component scope
const value = useMemo(() => ({
theme,
toggleTheme,
}), [theme, toggleTheme]);
return (
{children}
);
};
toggleTheme颿°ã空ã®äŸåé
åã§useCallbackã«ã©ããããããšã§ã颿°ã¯åæã¬ã³ããªã³ã°æã«äžåºŠã ãäœæãããããã«ãªããŸããããã«ãããã³ã³ããã¹ãã䜿çšããã³ã³ããŒãã³ãã®äžèŠãªåã¬ã³ããªã³ã°ãé²ãããŸãã
3. ãã£ãŒãæ¯èŒãšã€ãã¥ãŒã¿ãã«ãªããŒã¿
ããè€éãªã·ããªãªã§ã¯ãæ·±ããã¹ãããããªããžã§ã¯ããé
åãå«ãã³ã³ããã¹ãå€ãæ±ãããšããããŸãããããã®å ŽåãuseMemoãuseCallbackã䜿çšããŠãããªããžã§ã¯ããé
åã®åç
§ãåããŸãŸã§ãããã®äžã®å€ã倿ŽããããšäžèŠãªåã¬ã³ããªã³ã°ãçºçããå¯èœæ§ããããŸããããã«å¯ŸåŠããã«ã¯ã以äžã®äœ¿çšãæ€èšããå¿
èŠããããŸãïŒ
- ã€ãã¥ãŒã¿ãã«ãªããŒã¿æ§é ïŒ Immutable.jsãImmerã®ãããªã©ã€ãã©ãªã¯ãã€ãã¥ãŒã¿ãã«ãªããŒã¿ãæ±ãã®ã«åœ¹ç«ã¡ã倿Žãæ€åºããããããæå³ããªãå¯äœçšãé²ããŸããããŒã¿ãã€ãã¥ãŒã¿ãã«ã§ããå Žåã倿Žã¯æ¢åã®ãªããžã§ã¯ãããã¥ãŒããŒãããã®ã§ã¯ãªããæ°ãããªããžã§ã¯ããäœæããŸããããã«ãããå®éã®ããŒã¿å€æŽããã£ãå Žåã«åç §ã確å®ã«å€æŽãããŸãã
- ãã£ãŒãæ¯èŒïŒ ã€ãã¥ãŒã¿ãã«ãªããŒã¿ã䜿çšã§ããªãå Žåã倿Žãå®éã«çºçãããã©ããã倿ããããã«ã以åã®å€ãšçŸåšã®å€ããã£ãŒãæ¯èŒããå¿
èŠããããããããŸãããLodashã®ãããªã©ã€ãã©ãªã¯ããã£ãŒããªç䟡æ§ãã§ãã¯ã®ããã®ãŠãŒãã£ãªãã£é¢æ°ïŒäŸïŒ
_.isEqualïŒãæäŸããŸãããã ãããã£ãŒãæ¯èŒã¯ç¹ã«å€§ããªãªããžã§ã¯ãã«å¯ŸããŠã¯èšç®ã³ã¹ããé«ããªãå¯èœæ§ããããããããã©ãŒãã³ã¹ãžã®åœ±é¿ã«æ³šæããŠãã ããã
Immerã䜿çšããäŸïŒ
import React, { createContext, useState, useMemo, useCallback } from 'react';
import { produce } from 'immer';
export const DataContext = createContext();
export const DataProvider = ({ children }) => {
const [data, setData] = useState({
items: [
{ id: 1, name: 'Item 1', completed: false },
{ id: 2, name: 'Item 2', completed: true },
],
});
const updateItem = useCallback((id, updates) => {
setData(produce(draft => {
const itemIndex = draft.items.findIndex(item => item.id === id);
if (itemIndex !== -1) {
Object.assign(draft.items[itemIndex], updates);
}
}));
}, []);
const value = useMemo(() => ({
data,
updateItem,
}), [data, updateItem]);
return (
{children}
);
};
ãã®äŸã§ã¯ãImmerã®produce颿°ã«ãããitemsé
åã®åºã«ãªãããŒã¿ãå®éã«å€æŽãããå Žåã«ã®ã¿ãsetDataãç¶æ
æŽæ°ïŒã²ããŠã¯ã³ã³ããã¹ãå€ã®å€æŽïŒãããªã¬ãŒããããšãä¿èšŒãããŸãã
4. ã³ã³ããã¹ãã®éžæçå©çš
äžèŠãªåã¬ã³ããªã³ã°ãæžããããäžã€ã®æŠç¥ã¯ãã³ã³ããã¹ããããå°ãããããç²åºŠã®çްããã³ã³ããã¹ãã«åå²ããããšã§ããè€æ°ã®å€ãæã€åäžã®å€§ããªã³ã³ããã¹ããæã€ä»£ããã«ãããŒã¿ã®ç°ãªãéšåã«å¯ŸããŠå¥ã ã®ã³ã³ããã¹ããäœæã§ããŸããããã«ãããã³ã³ããŒãã³ãã¯å¿ èŠãªç¹å®ã®ã³ã³ããã¹ãã®ã¿ã賌èªã§ããã³ã³ããã¹ãå€ã倿Žããããšãã«åã¬ã³ããªã³ã°ãããã³ã³ããŒãã³ãã®æ°ãæå°éã«æããããšãã§ããŸãã
äŸãã°ããŠãŒã¶ãŒããŒã¿ãããŒãèšå®ããã®ä»ã®ã°ããŒãã«ãªç¶æ
ãå«ãåäžã®AppContextã®ä»£ããã«ãå¥ã
ã®UserContextãThemeContextãSettingsContextãæã€ããšãã§ããŸããã³ã³ããŒãã³ãã¯ãå¿
èŠãªã³ã³ããã¹ãã®ã¿ã賌èªãããããé¢é£ã®ãªãããŒã¿ã倿Žããããšãã®äžèŠãªåã¬ã³ããªã³ã°ãé¿ããããšãã§ããŸãã
å®äžçã®äŸãšåœéåã«é¢ããèæ ®äºé
ãããã®æé©åæè¡ã¯ãè€éãªç¶æ 管çãé«é »åºŠã®æŽæ°ãããã¢ããªã±ãŒã·ã§ã³ã§ã¯ç¹ã«éèŠã§ãã以äžã®ã·ããªãªãèããŠã¿ãŠãã ããïŒ
- Eã³ããŒã¹ã¢ããªã±ãŒã·ã§ã³ïŒ ãŠãŒã¶ãŒãååã远å ãŸãã¯åé€ããã«ã€ããŠé »ç¹ã«æŽæ°ãããã·ã§ããã³ã°ã«ãŒãã³ã³ããã¹ããã¡ã¢åã«ãããååäžèЧããŒãžäžã®ç¡é¢ä¿ãªã³ã³ããŒãã³ãã®åã¬ã³ããªã³ã°ãé²ãããšãã§ããŸãããŠãŒã¶ãŒã®æåšå°ã«åºã¥ããŠé貚ã衚瀺ããïŒäŸïŒç±³åœã§ã¯USDããšãŒãããã§ã¯EURãæ¥æ¬ã§ã¯JPYïŒããšãã³ã³ããã¹ãã§åŠçããã¡ã¢åããããšã§ããŠãŒã¶ãŒãåãå Žæã«ããéã®æŽæ°ãé¿ããããšãã§ããŸãã
- ãªã¢ã«ã¿ã€ã ããŒã¿ããã·ã¥ããŒãïŒ ã¹ããªãŒãã³ã°ããŒã¿æŽæ°ãæäŸããã³ã³ããã¹ããéå°ãªåã¬ã³ããªã³ã°ãé²ããå¿çæ§ãç¶æããããã«ã¯ã¡ã¢åãäžå¯æ¬ ã§ããæ¥ä»ãšæå»ã®åœ¢åŒããŠãŒã¶ãŒã®å°åã«ããŒã«ã©ã€ãºãããŠããããšïŒäŸïŒ
toLocaleDateStringãštoLocaleTimeStringã䜿çšïŒãããã³UIãi18nã©ã€ãã©ãªã䜿çšããŠç°ãªãèšèªã«é©å¿ããããšã確èªããŠãã ããã - å ±åããã¥ã¡ã³ããšãã£ã¿ïŒ å ±æããã¥ã¡ã³ãã®ç¶æ ã管çããã³ã³ããã¹ãããã¹ãŠã®ãŠãŒã¶ãŒã«ãšã£ãŠã¹ã ãŒãºãªç·šéäœéšãç¶æããããã«ã¯ãå¹ççãªæŽæ°ãéèŠã§ãã
ã°ããŒãã«ãªãŠãŒã¶ãŒåãã«ã¢ããªã±ãŒã·ã§ã³ãéçºããéã«ã¯ã次ã®ç¹ãèæ ®ããããšãå¿ããªãã§ãã ããïŒ
- ããŒã«ãªãŒãŒã·ã§ã³ïŒi18nïŒïŒ
react-i18nextãlinguiã®ãããªã©ã€ãã©ãªã䜿çšããŠãã¢ããªã±ãŒã·ã§ã³ãè€æ°ã®èšèªã«ç¿»èš³ããŸããContextã䜿çšããŠãçŸåšéžæãããŠããèšèªãä¿åãã翻蚳ãããæååãã³ã³ããŒãã³ãã«æäŸã§ããŸãã - å°åããšã®ããŒã¿åœ¢åŒïŒ æ¥ä»ãæ°å€ãé貚ããŠãŒã¶ãŒã®ãã±ãŒã«ã«åŸã£ãŠãã©ãŒãããããŸãã
- ã¿ã€ã ãŸãŒã³ïŒ äžçã®ç°ãªãå Žæã«ãããŠãŒã¶ãŒã«å¯ŸããŠã€ãã³ããç· ãåããæ£ç¢ºã«è¡šç€ºãããããã«ãã¿ã€ã ãŸãŒã³ãæ£ããåŠçããŸãã
moment-timezoneãdate-fns-tzã®ãããªã©ã€ãã©ãªã®äœ¿çšãæ€èšããŠãã ããã - å³ããå·ŠïŒRTLïŒãžã®ã¬ã€ã¢ãŠãïŒ ã¢ã©ãã¢èªãããã©ã€èªã®ãããªRTLèšèªããµããŒãããããã«ãã¢ããªã±ãŒã·ã§ã³ã®ã¬ã€ã¢ãŠãã調æŽããŸãã
å®è·µçãªæŽå¯ãšãã¹ããã©ã¯ãã£ã¹
React Context Providerã®ããã©ãŒãã³ã¹ãæé©åããããã®ãã¹ããã©ã¯ãã£ã¹ã®æŠèŠã¯æ¬¡ã®ãšããã§ãïŒ
useMemoã䜿çšããŠã³ã³ããã¹ãå€ãã¡ã¢åãããuseCallbackã䜿çšããŠã³ã³ããã¹ãçµç±ã§æž¡ããã颿°ãã¡ã¢åããã- è€éãªãªããžã§ã¯ããé åãæ±ãå Žåã¯ãã€ãã¥ãŒã¿ãã«ãªããŒã¿æ§é ãŸãã¯ãã£ãŒãæ¯èŒã䜿çšããã
- 倧ããªã³ã³ããã¹ããããå°ãããããç²åºŠã®çްããã³ã³ããã¹ãã«åå²ããã
- ã¢ããªã±ãŒã·ã§ã³ããããã¡ã€ãªã³ã°ããŠããã©ãŒãã³ã¹ã®ããã«ããã¯ãç¹å®ããæé©åã®åœ±é¿ã枬å®ããã åã¬ã³ããªã³ã°ãåæããããã«React DevToolsã䜿çšããŠãã ããã
useMemoãšuseCallbackã«æž¡ãäŸåé¢ä¿ã«æ³šæããã äžæ£ç¢ºãªäŸåé¢ä¿ã¯ãæŽæ°ã®èŠéããäžèŠãªåã¬ã³ããªã³ã°ã«ã€ãªããå¯èœæ§ããããŸãã- ããè€éãªç¶æ 管çã·ããªãªã§ã¯ãReduxãZustandã®ãããªç¶æ 管çã©ã€ãã©ãªã®äœ¿çšãæ€èšããã ãããã®ã©ã€ãã©ãªã¯ãã»ã¬ã¯ã¿ãŒãããã«ãŠã§ã¢ã®ãããªé«åºŠãªæ©èœãæäŸããããã©ãŒãã³ã¹ã®æé©åã«åœ¹ç«ã¡ãŸãã
çµè«
React Context Providerã®ããã©ãŒãã³ã¹ãæé©åããããšã¯ãå¹ççã§å¿çæ§ã®é«ãã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããã«äžå¯æ¬ ã§ããã³ã³ããã¹ãæŽæ°ã®æœåšçãªèœãšã穎ãçè§£ããã¡ã¢åãã³ã³ããã¹ãã®éžæçå©çšãªã©ã®æè¡ãé©çšããããšã§ãã¢ããªã±ãŒã·ã§ã³ã®è€éãã«é¢ããããã¹ã ãŒãºã§æ¥œãããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãæäŸã§ããŸããåžžã«ã¢ããªã±ãŒã·ã§ã³ããããã¡ã€ãªã³ã°ããæé©åã®åœ±é¿ã枬å®ããŠãå®éã«éããçã¿åºããŠããããšã確èªããããšãå¿ããªãã§ãã ããã