React SuspenseãšãªãœãŒã¹ç¡å¹åæŠç¥ãçšããŠãã£ãã·ã¥ã®æå¹æéã广çã«ç®¡çããã¢ããªã±ãŒã·ã§ã³ã®ããã©ãŒãã³ã¹ãšããŒã¿æŽåæ§ãæé©åããæ¹æ³ãåŠã³ãŸãã
React Suspenseã®ãªãœãŒã¹ç¡å¹åïŒãã£ãã·ã¥æå¹æé管çããã¹ã¿ãŒãã
React Suspenseã¯ãã¢ããªã±ãŒã·ã§ã³ã«ãããéåæããŒã¿ãã§ããã³ã°ã®æ±ãæ¹ã«é©åœããããããŸãããããããåã«Suspenseã䜿çšããã ãã§ã¯äžååã§ãããã£ãã·ã¥ãã©ã®ããã«ç®¡çããããŒã¿ã®æŽåæ§ã確ä¿ããããæ éã«æ€èšããå¿ èŠããããŸãããªãœãŒã¹ã®ç¡å¹åãç¹ã«ãã£ãã·ã¥ã®æå¹æéåãã¯ããã®ããã»ã¹ã®éèŠãªåŽé¢ã§ãããã®èšäºã§ã¯ãReact Suspenseã§å¹æçãªãã£ãã·ã¥æå¹æéæŠç¥ãçè§£ããå®è£ ããããã®å æ¬çãªã¬ã€ããæäŸããŸãã
åé¡ã®çè§£ïŒå€ãããŒã¿ãšç¡å¹åã®å¿ èŠæ§
ãªã¢ãŒããœãŒã¹ãããã§ããããããŒã¿ãæ±ãã¢ããªã±ãŒã·ã§ã³ã§ã¯ãå€ãããŒã¿ãçºçããå¯èœæ§ããããŸãã å€ãããŒã¿ãšã¯ããŠãŒã¶ãŒã«è¡šç€ºãããŠããæ å ±ãææ°ããŒãžã§ã³ã§ã¯ãªããªã£ãç¶æ ãæããŸããããã¯ããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã®äœäžãäžæ£ç¢ºãªæ å ±ãããã«ã¯ã¢ããªã±ãŒã·ã§ã³ãšã©ãŒã«ã€ãªããå¯èœæ§ããããŸãããªãœãŒã¹ã®ç¡å¹åãšãã£ãã·ã¥ã®æå¹æéãäžå¯æ¬ ã§ããçç±ã¯æ¬¡ã®ãšããã§ãïŒ
- ããŒã¿ã®æ®çºæ§ïŒ äžéšã®ããŒã¿ã¯é »ç¹ã«å€æŽãããŸãïŒäŸïŒæ ªäŸ¡ããœãŒã·ã£ã«ã¡ãã£ã¢ã®ãã£ãŒãããªã¢ã«ã¿ã€ã åæïŒã ç¡å¹åãè¡ããªããšãã¢ããªã±ãŒã·ã§ã³ã¯å€ãæ å ±ã衚瀺ããŠããŸãå¯èœæ§ããããŸããééã£ãæ ªäŸ¡ã衚瀺ããéèã¢ããªã±ãŒã·ã§ã³ãæ³åããŠã¿ãŠãã ããããã®çµæã¯é倧ãªãã®ã«ãªãåŸãŸãã
- ãŠãŒã¶ãŒã¢ã¯ã·ã§ã³ïŒ ãŠãŒã¶ãŒã®æäœïŒäŸïŒããŒã¿ã®äœæãæŽæ°ãåé€ïŒã¯ã倿Žãåæ ããããã«ãã£ãã·ã¥ãããããŒã¿ãç¡å¹åããå¿ èŠãããããšããããããŸãã äŸãã°ããŠãŒã¶ãŒããããã£ãŒã«åçãæŽæ°ããå Žåãã¢ããªã±ãŒã·ã§ã³ã®ä»ã®å Žæã«è¡šç€ºãããŠãããã£ãã·ã¥ãããããŒãžã§ã³ã¯ç¡å¹åãããåãã§ãããããå¿ èŠããããŸãã
- ãµãŒããŒãµã€ãã®æŽæ°ïŒ ãŠãŒã¶ãŒã¢ã¯ã·ã§ã³ããªããŠããå€éšèŠå ãããã¯ã°ã©ãŠã³ãããã»ã¹ã«ãã£ãŠãµãŒããŒãµã€ãã®ããŒã¿ã倿ŽãããããšããããŸããäŸãã°ãã³ã³ãã³ã管çã·ã¹ãã ãèšäºãæŽæ°ããå Žåãã¯ã©ã€ã¢ã³ããµã€ãã«ãããã®èšäºã®ãã£ãã·ã¥ãããããŒãžã§ã³ãç¡å¹åããå¿ èŠããããŸãã
ãã£ãã·ã¥ãé©åã«ç¡å¹åã§ããªããšããŠãŒã¶ãŒãå€ãæ å ±ãèŠãããäžæ£ç¢ºãªããŒã¿ã«åºã¥ããŠæ±ºå®ãäžããããã¢ããªã±ãŒã·ã§ã³å ã§äžæŽåãçµéšãããããå¯èœæ§ããããŸãã
React SuspenseãšããŒã¿ãã§ããã³ã°ïŒç°¡åãªãŸãšã
ãªãœãŒã¹ã®ç¡å¹åã«æ·±ãå ¥ãåã«ãReact SuspenseãããŒã¿ãã§ããã³ã°ãšã©ã®ããã«é£æºããããç°¡åã«æ¯ãè¿ã£ãŠã¿ãŸããããSuspenseã¯ãããŒã¿ãã§ããã³ã°ãªã©ã®éåææäœãå®äºããã®ãåŸ ã€éãã³ã³ããŒãã³ããã¬ã³ããªã³ã°ããäžæåæ¢ãããããšãå¯èœã«ããŸããããã«ãããããŒãã£ã³ã°ç¶æ ããšã©ãŒããŠã³ããªã宣èšçã«æ±ãã¢ãããŒããå¯èœã«ãªããŸãã
Suspenseã¯ãŒã¯ãããŒã®äž»èŠãªã³ã³ããŒãã³ãã¯æ¬¡ã®ãšããã§ãïŒ
- SuspenseïŒ `<Suspense>`ã³ã³ããŒãã³ãã䜿çšãããšãäžæåæ¢ããå¯èœæ§ã®ããã³ã³ããŒãã³ããã©ããã§ããŸãã ããã¯`fallback`ãããããåããäžæåæ¢ããã³ã³ããŒãã³ããããŒã¿ãåŸ ã£ãŠããéã«ã¬ã³ããªã³ã°ãããŸãã
- ãšã©ãŒããŠã³ããªïŒ ãšã©ãŒããŠã³ããªã¯ã¬ã³ããªã³ã°äžã«çºçãããšã©ãŒããã£ããããäžæåæ¢ããã³ã³ããŒãã³ãã®å€±æãé©åã«åŠçããã¡ã«ããºã ãæäŸããŸãã
- ããŒã¿ãã§ããã³ã°ã©ã€ãã©ãªïŒäŸïŒ`react-query`, `SWR`, `urql`ïŒïŒ ãããã®ã©ã€ãã©ãªã¯ãããŒã¿ã®ãã§ãããçµæã®ãã£ãã·ã¥ãããŒãã£ã³ã°ããã³ãšã©ãŒç¶æ ã®åŠçã®ããã®ããã¯ãšãŠãŒãã£ãªãã£ãæäŸããŸãããããã¯ãã°ãã°Suspenseãšã·ãŒã ã¬ã¹ã«çµ±åãããŸãã
`react-query`ãšSuspenseã䜿çšããç°¡åãªäŸã以äžã«ç€ºããŸãïŒ
import { useQuery } from 'react-query';
import React from 'react';
const fetchUserData = async (userId) => {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) {
throw new Error('Failed to fetch user data');
}
return response.json();
};
function UserProfile({ userId }) {
const { data: user } = useQuery(['user', userId], () => fetchUserData(userId), { suspense: true });
return (
<div>
<h2>{user.name}</h2>
<p>Email: {user.email}</p>
</div>
);
}
function App() {
return (
<Suspense fallback={<div>Loading user data...</div>}>
<UserProfile userId="123" />
</Suspense>
);
}
export default App;
ãã®äŸã§ã¯ã`react-query`ã®`useQuery`ããŠãŒã¶ãŒããŒã¿ããã§ããããåŸ æ©äžã«`UserProfile`ã³ã³ããŒãã³ããäžæåæ¢ãããŸãã`<Suspense>`ã³ã³ããŒãã³ãã¯ãã©ãŒã«ããã¯ãšããŠããŒãã£ã³ã°ã€ã³ãžã±ãŒã¿ãŒã衚瀺ããŸãã
ãã£ãã·ã¥ã®æå¹æéãšç¡å¹åã®æŠç¥
ã§ã¯ãReact Suspenseã¢ããªã±ãŒã·ã§ã³ã§ãã£ãã·ã¥ã®æå¹æéãšç¡å¹åã管çããããã®ããŸããŸãªæŠç¥ãæ¢ã£ãŠã¿ãŸãããïŒ
1. æéããŒã¹ã®æå¹æéïŒTTL - Time To LiveïŒ
æéããŒã¹ã®æå¹æéã§ã¯ããã£ãã·ã¥ãããããŒã¿ã«æå€§çåæéïŒTTLïŒãèšå®ããŸããTTLãåãããšãããŒã¿ã¯å€ããšèŠãªãããæ¬¡ã®ãªã¯ãšã¹ãã§åãã§ãããããŸããããã¯ã·ã³ãã«ã§äžè¬çãªã¢ãããŒãã§ãããããŸãé »ç¹ã«å€æŽãããªãããŒã¿ã«é©ããŠããŸãã
å®è£ ïŒ ã»ãšãã©ã®ããŒã¿ãã§ããã³ã°ã©ã€ãã©ãªã¯ãTTLãèšå®ããããã®ãªãã·ã§ã³ãæäŸããŠããŸããäŸãã°ã`react-query`ã§ã¯ã`staleTime`ãªãã·ã§ã³ã䜿çšã§ããŸãïŒ
import { useQuery } from 'react-query';
const fetchUserData = async (userId) => { ... };
function UserProfile({ userId }) {
const { data: user } = useQuery(['user', userId], () => fetchUserData(userId), {
suspense: true,
staleTime: 60 * 1000, // 60ç§ïŒ1åïŒ
});
return (
<div>
<h2>{user.name}</h2>
<p>Email: {user.email}</p>
</div>
);
}
ãã®äŸã§ã¯ã`staleTime`ã60ç§ã«èšå®ãããŠããŸãã ããã¯ãæåã®ãã§ãããã60ç§ä»¥å ã«ãŠãŒã¶ãŒããŒã¿ãå床ã¢ã¯ã»ã¹ãããå Žåããã£ãã·ã¥ãããããŒã¿ã䜿çšãããããšãæå³ããŸãã60ç§åŸãããŒã¿ã¯å€ããšèŠãªããã`react-query`ã¯ããã¯ã°ã©ãŠã³ãã§èªåçã«åãã§ããããŸãã`cacheTime`ãªãã·ã§ã³ã¯ãéã¢ã¯ãã£ããªãã£ãã·ã¥ããŒã¿ãä¿æãããæéãæ±ºå®ããŸããèšå®ããã`cacheTime`å ã«ã¢ã¯ã»ã¹ãããªãå ŽåãããŒã¿ã¯ã¬ããŒãžã³ã¬ã¯ã·ã§ã³ãããŸãã
èæ ®äºé ïŒ
- é©åãªTTLã®éžæïŒ TTLã®å€ã¯ããŒã¿ã®æ®çºæ§ã«äŸåããŸããæ¥éã«å€åããããŒã¿ã«ã¯çãTTLãå¿ èŠã§ããæ¯èŒçéçãªããŒã¿ã«ã¯é·ãTTLãããã©ãŒãã³ã¹ãåäžãããããšãã§ããŸããé©åãªãã©ã³ã¹ãèŠã€ããã«ã¯æ éãªæ€èšãå¿ èŠã§ããå®éšãšã¢ãã¿ãªã³ã°ã¯ãæé©ãªTTLå€ã決å®ããã®ã«åœ¹ç«ã¡ãŸãã
- ã°ããŒãã«TTL vs. ç²åºŠã®çްããTTLïŒ ãã¹ãŠã®ãã£ãã·ã¥ããŒã¿ã«ã°ããŒãã«TTLãèšå®ããããç¹å®ã®ãªãœãŒã¹ã«ç°ãªãTTLãèšå®ããããšãã§ããŸããç²åºŠã®çްããTTLã䜿çšãããšãåããŒã¿ãœãŒã¹ã®åºæã®ç¹æ§ã«åºã¥ããŠãã£ãã·ã¥ã®åäœãæé©åã§ããŸããäŸãã°ãé »ç¹ã«æŽæ°ãããååäŸ¡æ Œã¯ãããŸã倿ŽãããªããŠãŒã¶ãŒãããã£ãŒã«æ å ±ãããçãTTLãæã€ãããããŸããã
- CDNãã£ãã·ã³ã°ïŒ ã³ã³ãã³ãããªããªãŒãããã¯ãŒã¯ïŒCDNïŒã䜿çšããŠããå ŽåãCDNãããŒã¿ããã£ãã·ã¥ããããšãå¿ããªãã§ãã ãããäžè²«ããåäœã確ä¿ããããã«ãã¯ã©ã€ã¢ã³ããµã€ãã®TTLãCDNã®ãã£ãã·ã¥èšå®ãšèª¿æŽããå¿ èŠããããŸããCDNã®èšå®ãäžé©åã ãšãã¯ã©ã€ã¢ã³ããµã€ãã§ã®é©åãªç¡å¹åã«ãããããããå€ãããŒã¿ããŠãŒã¶ãŒã«æäŸãããå¯èœæ§ããããŸãã
2. ã€ãã³ãããŒã¹ã®ç¡å¹åïŒæåç¡å¹åïŒ
ã€ãã³ãããŒã¹ã®ç¡å¹åã§ã¯ãç¹å®ã®ã€ãã³ããçºçãããšãã«æç€ºçã«ãã£ãã·ã¥ãç¡å¹åããŸããããã¯ãç¹å®ã®ãŠãŒã¶ãŒã¢ã¯ã·ã§ã³ããµãŒããŒãµã€ãã®ã€ãã³ãã«ãã£ãŠããŒã¿ã倿Žãããããšãããã£ãŠããå Žåã«é©ããŠããŸãã
å®è£ ïŒ ããŒã¿ãã§ããã³ã°ã©ã€ãã©ãªã¯éåžžããã£ãã·ã¥ãšã³ããªãæåã§ç¡å¹åããããã®ã¡ãœãããæäŸããŸãã`react-query`ã§ã¯ã`queryClient.invalidateQueries`ã¡ãœããã䜿çšã§ããŸãïŒ
import { useQueryClient } from 'react-query';
function UpdateProfileButton({ userId }) {
const queryClient = useQueryClient();
const handleUpdate = async () => {
// ... ãµãŒããŒã§ãŠãŒã¶ãŒãããã£ãŒã«ããŒã¿ãæŽæ°
// ãŠãŒã¶ãŒããŒã¿ãã£ãã·ã¥ãç¡å¹å
queryClient.invalidateQueries(['user', userId]);
};
return <button onClick={handleUpdate}>Update Profile</button>;
}
ãã®äŸã§ã¯ããµãŒããŒã§ãŠãŒã¶ãŒãããã£ãŒã«ãæŽæ°ãããåŸã`queryClient.invalidateQueries(['user', userId])`ãåŒã³åºãããŠã察å¿ãããã£ãã·ã¥ãšã³ããªãç¡å¹åãããŸããæ¬¡ã«`UserProfile`ã³ã³ããŒãã³ããã¬ã³ããªã³ã°ããããšããããŒã¿ã¯åãã§ãããããŸãã
èæ ®äºé ïŒ
- ç¡å¹åã€ãã³ãã®ç¹å®ïŒ ã€ãã³ãããŒã¹ã®ç¡å¹åã®éµã¯ãããŒã¿å€æŽãããªã¬ãŒããã€ãã³ããæ£ç¢ºã«ç¹å®ããããšã§ããããã«ã¯ããŠãŒã¶ãŒã¢ã¯ã·ã§ã³ã®è¿œè·¡ããµãŒããŒéä¿¡ã€ãã³ãïŒSSEïŒã®ãªãã¹ã³ããŸãã¯ãªã¢ã«ã¿ã€ã æŽæ°ãåä¿¡ããããã®WebSocketã®äœ¿çšãªã©ãå«ãŸããå ŽåããããŸããå¿ èŠãªãšãã«åžžã«ãã£ãã·ã¥ãç¡å¹åãããããã«ããã«ã¯ãå ç¢ãªã€ãã³ã远跡ã·ã¹ãã ãäžå¯æ¬ ã§ãã
- ç²åºŠã®çްããç¡å¹åïŒ ãã£ãã·ã¥å šäœãç¡å¹åããã®ã§ã¯ãªããã€ãã³ãã®åœ±é¿ãåããç¹å®ã®ãã£ãã·ã¥ãšã³ããªã®ã¿ãç¡å¹åããããã«ããŠãã ãããããã«ãããäžèŠãªåãã§ãããæå°éã«æããããããã©ãŒãã³ã¹ãåäžããŸãã`queryClient.invalidateQueries`ã¡ãœããã¯ãã¯ãšãªããŒã«åºã¥ããŠéžæçãªç¡å¹åãå¯èœã«ããŸãã
- ãªããã£ãã¹ãã£ãã¯æŽæ°ïŒæ¥œèŠ³çæŽæ°ïŒïŒ ããŒã¿ãããã¯ã°ã©ãŠã³ãã§æŽæ°ãããŠããéã«ãŠãŒã¶ãŒã«å³æã®ãã£ãŒãããã¯ãæäŸããããã«ããªããã£ãã¹ãã£ãã¯æŽæ°ã®äœ¿çšãæ€èšããŠãã ããããªããã£ãã¹ãã£ãã¯æŽæ°ã§ã¯ãUIãå³åº§ã«æŽæ°ãããµãŒããŒãµã€ãã®æŽæ°ã倱æããå Žåã«å€æŽãå ã«æ»ããŸããããã«ãããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã¯åäžããŸãããæ éãªãšã©ãŒãã³ããªã³ã°ãšãããè€éã«ãªãå¯èœæ§ã®ãããã£ãã·ã¥ç®¡çãå¿ èŠã§ãã
3. ã¿ã°ããŒã¹ã®ç¡å¹å
ã¿ã°ããŒã¹ã®ç¡å¹åã§ã¯ããã£ãã·ã¥ãããããŒã¿ã«ã¿ã°ãé¢é£ä»ããããšãã§ããŸããããŒã¿ã倿Žããããšãç¹å®ã®ã¿ã°ã«é¢é£ä»ãããããã¹ãŠã®ãã£ãã·ã¥ãšã³ããªãç¡å¹åããŸããããã¯ãè€æ°ã®ãã£ãã·ã¥ãšã³ããªãåãåºç€ããŒã¿ã«äŸåããã·ããªãªã§åœ¹ç«ã¡ãŸãã
å®è£ ïŒ ããŒã¿ãã§ããã³ã°ã©ã€ãã©ãªã¯ãã¿ã°ããŒã¹ã®ç¡å¹åãçŽæ¥ãµããŒãããŠããå Žåãšããã§ãªãå ŽåããããŸããã©ã€ãã©ãªã®ãã£ãã·ã³ã°æ©èœã®äžã«ç¬èªã®ã¿ã°ä»ãã¡ã«ããºã ãå®è£ ããå¿ èŠããããããããŸãããäŸãã°ãã¿ã°ãã¯ãšãªããŒã«ãããã³ã°ããå¥ã®ããŒã¿æ§é ãç¶æããããšãã§ããŸããã¿ã°ãç¡å¹åããå¿ èŠãããå Žåãé¢é£ããã¯ãšãªããŒãå埩åŠçãããããã®ã¯ãšãªãç¡å¹åããŸãã
äŸïŒæŠå¿µïŒïŒ
// ç°¡åãªäŸ - å®éã®å®è£
ã¯ç°ãªããŸã
const tagMap = {
'products': [['product', 1], ['product', 2], ['product', 3]],
'categories': [['category', 'electronics'], ['category', 'clothing']],
};
function invalidateByTag(tag) {
const queryClient = useQueryClient();
const queryKeys = tagMap[tag];
if (queryKeys) {
queryKeys.forEach(key => queryClient.invalidateQueries(key));
}
}
// ååãæŽæ°ããããšãïŒ
invalidateByTag('products');
èæ ®äºé ïŒ
- ã¿ã°ç®¡çïŒ ã¿ã°ãšã¯ãšãªããŒã®ãããã³ã°ãé©åã«ç®¡çããããšãéèŠã§ããé¢é£ãããã£ãã·ã¥ãšã³ããªã«ã¿ã°ãäžè²«ããŠé©çšãããããã«ããå¿ èŠããããŸããããŒã¿ã®æŽåæ§ãç¶æããããã«ã¯ãå¹ççãªã¿ã°ç®¡çã·ã¹ãã ãäžå¯æ¬ ã§ãã
- è€éãïŒ ã¿ã°ããŒã¹ã®ç¡å¹åã¯ãç¹ã«å€æ°ã®ã¿ã°ãšé¢ä¿ãããå Žåãã¢ããªã±ãŒã·ã§ã³ã«è€éããå ããå¯èœæ§ããããŸããããã©ãŒãã³ã¹ã®ããã«ããã¯ãä¿å®æ§ã®åé¡ãåé¿ããããã«ãã¿ã°ä»ãæŠç¥ãæ éã«èšèšããããšãéèŠã§ãã
- ã©ã€ãã©ãªã®ãµããŒãïŒ äœ¿çšããŠããããŒã¿ãã§ããã³ã°ã©ã€ãã©ãªãã¿ã°ããŒã¹ã®ç¡å¹åãçµã¿èŸŒã¿ã§ãµããŒãããŠãããããŸãã¯èªåã§å®è£ ããå¿ èŠããããã確èªããŠãã ãããäžéšã®ã©ã€ãã©ãªã¯ãã¿ã°ããŒã¹ã®ç¡å¹åãç°¡çŽ åããæ¡åŒµæ©èœãããã«ãŠã§ã¢ãæäŸããŠããå ŽåããããŸãã
4. ãªã¢ã«ã¿ã€ã ç¡å¹åã®ããã®ãµãŒããŒéä¿¡ã€ãã³ãïŒSSEïŒãŸãã¯WebSocket
ãªã¢ã«ã¿ã€ã ã®ããŒã¿æŽæ°ãå¿ èŠãšããã¢ããªã±ãŒã·ã§ã³ã§ã¯ããµãŒããŒéä¿¡ã€ãã³ãïŒSSEïŒãŸãã¯WebSocketã䜿çšããŠããµãŒããŒããã¯ã©ã€ã¢ã³ãã«ç¡å¹åéç¥ãããã·ã¥ã§ããŸãããµãŒããŒã§ããŒã¿ã倿ŽããããšããµãŒããŒã¯ã¯ã©ã€ã¢ã³ãã«ã¡ãã»ãŒãžãéä¿¡ããç¹å®ã®ãã£ãã·ã¥ãšã³ããªãç¡å¹åããããã«æç€ºããŸãã
å®è£ ïŒ
- æ¥ç¶ã®ç¢ºç«ïŒ ã¯ã©ã€ã¢ã³ããšãµãŒããŒéã«SSEãŸãã¯WebSocketæ¥ç¶ãã»ããã¢ããããŸãã
- ãµãŒããŒãµã€ãããžãã¯ïŒ ãµãŒããŒã§ããŒã¿ã倿Žãããããæ¥ç¶ãããŠããã¯ã©ã€ã¢ã³ãã«ã¡ãã»ãŒãžãéä¿¡ããŸããã¡ãã»ãŒãžã«ã¯ãã©ã®ãã£ãã·ã¥ãšã³ããªãç¡å¹åããå¿ èŠããããã«ã€ããŠã®æ å ±ïŒäŸïŒã¯ãšãªããŒãã¿ã°ïŒãå«ããå¿ èŠããããŸãã
- ã¯ã©ã€ã¢ã³ããµã€ãããžãã¯ïŒ ã¯ã©ã€ã¢ã³ãåŽã§ã¯ããµãŒããŒããã®ç¡å¹åã¡ãã»ãŒãžããªãã¹ã³ããããŒã¿ãã§ããã³ã°ã©ã€ãã©ãªã®ç¡å¹åã¡ãœããã䜿çšããŠå¯Ÿå¿ãããã£ãã·ã¥ãšã³ããªãç¡å¹åããŸãã
äŸïŒSSEã䜿çšããæŠå¿µïŒïŒ
// ãµãŒããŒãµã€ã (Node.js)
const express = require('express');
const app = express();
const clients = [];
app.get('/events', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
const clientId = Date.now();
const newClient = {
id: clientId,
res,
};
clients.push(newClient);
req.on('close', () => {
clients = clients.filter(client => client.id !== clientId);
});
res.write('data: connected\n\n');
});
function sendInvalidation(queryKey) {
clients.forEach(client => {
client.res.write(`data: ${JSON.stringify({ type: 'invalidate', queryKey: queryKey })}\n\n`);
});
}
// äŸïŒååããŒã¿ã倿ŽããããšãïŒ
sendInvalidation(['product', 123]);
app.listen(4000, () => {
console.log('SSE server listening on port 4000');
});
// ã¯ã©ã€ã¢ã³ããµã€ã (React)
import { useQueryClient } from 'react-query';
import { useEffect } from 'react';
function App() {
const queryClient = useQueryClient();
useEffect(() => {
const eventSource = new EventSource('/events');
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'invalidate') {
queryClient.invalidateQueries(data.queryKey);
}
};
eventSource.onerror = (error) => {
console.error('SSE error:', error);
eventSource.close();
};
return () => {
eventSource.close();
};
}, [queryClient]);
// ... ã¢ããªã±ãŒã·ã§ã³ã®æ®ã
}
èæ ®äºé ïŒ
- ã¹ã±ãŒã©ããªãã£ïŒ SSEãšWebSocketã¯ãç¹ã«æ¥ç¶ã¯ã©ã€ã¢ã³ãæ°ãå€ãå ŽåããªãœãŒã¹ã倧éã«æ¶è²»ããå¯èœæ§ããããŸããã¹ã±ãŒã©ããªãã£ãžã®åœ±é¿ãæ éã«æ€èšããããã«å¿ããŠãµãŒããŒãµã€ãã®ã€ã³ãã©ãæé©åããŠãã ãããããŒããã©ã³ã·ã³ã°ãã³ãã¯ã·ã§ã³ããŒãªã³ã°ã¯ãã¹ã±ãŒã©ããªãã£ã®åäžã«åœ¹ç«ã¡ãŸãã
- ä¿¡é Œæ§ïŒ SSEãŸãã¯WebSocketæ¥ç¶ãä¿¡é Œã§ãããããã¯ãŒã¯ã®åæã«å¯ŸããŠå埩åãããããšã確èªããŠãã ãããæ¥ç¶ã倱ãããå Žåã«èªåçã«å確ç«ããããã«ãã¯ã©ã€ã¢ã³ããµã€ãã«åæ¥ç¶ããžãã¯ãå®è£ ããŸãã
- ã»ãã¥ãªãã£ïŒ äžæ£ã¢ã¯ã»ã¹ãããŒã¿æŒæŽ©ãé²ãããã«ãSSEãŸãã¯WebSocketãšã³ããã€ã³ããä¿è·ããŠãã ãããèªèšŒããã³èªå¯ã¡ã«ããºã ã䜿çšããŠãèªå¯ãããã¯ã©ã€ã¢ã³ãã®ã¿ãç¡å¹åéç¥ãåä¿¡ã§ããããã«ããŸãã
- è€éãïŒ ãªã¢ã«ã¿ã€ã ã®ç¡å¹åãå®è£ ãããšãã¢ããªã±ãŒã·ã§ã³ã®è€éããå¢ããŸãããªã¢ã«ã¿ã€ã æŽæ°ã®å©ç¹ãšã远å ãããè€éããã¡ã³ããã³ã¹ã®ãªãŒããŒããããæ éã«æ¯èŒæ€èšããŠãã ããã
React Suspenseã§ã®ãªãœãŒã¹ç¡å¹åã®ãã¹ããã©ã¯ãã£ã¹
React Suspenseã§ãªãœãŒã¹ç¡å¹åãå®è£ ããéã«å¿ã«çããŠããã¹ããã¹ããã©ã¯ãã£ã¹ãããã€ã玹ä»ããŸãïŒ
- é©åãªæŠç¥ãéžæããïŒ ã¢ããªã±ãŒã·ã§ã³ã®ç¹å®ã®ããŒãºãšããŒã¿ã®ç¹æ§ã«æãé©ããç¡å¹åæŠç¥ãéžæããŠãã ãããããŒã¿ã®æ®çºæ§ãæŽæ°é »åºŠãã¢ããªã±ãŒã·ã§ã³ã®è€éããèæ ®ããŸããã¢ããªã±ãŒã·ã§ã³ã®ç°ãªãéšåã«ã¯ãæŠç¥ã®çµã¿åãããé©åãªå ŽåããããŸãã
- ç¡å¹åã®ç¯å²ãæå°éã«ããïŒ ããŒã¿å€æŽã®åœ±é¿ãåããç¹å®ã®ãã£ãã·ã¥ãšã³ããªã®ã¿ãç¡å¹åããŸããäžå¿ èŠã«ãã£ãã·ã¥å šäœãç¡å¹åããããšã¯é¿ããŠãã ããã
- ç¡å¹åã®ãããŠã³ã¹ïŒ è€æ°ã®ç¡å¹åã€ãã³ããç«ãŠç¶ãã«çºçããå Žåã¯ãéå°ãªåãã§ãããé¿ããããã«ç¡å¹åããã»ã¹ããããŠã³ã¹ããŸããããã¯ããŠãŒã¶ãŒå ¥åãé »ç¹ãªãµãŒããŒãµã€ãã®æŽæ°ãåŠçããéã«ç¹ã«åœ¹ç«ã¡ãŸãã
- ãã£ãã·ã¥ããã©ãŒãã³ã¹ã®ç£èŠïŒ ãã£ãã·ã¥ã®ãããçãåãã§ããæéããã®ä»ã®ããã©ãŒãã³ã¹ã¡ããªã¯ã¹ã远跡ããŠãæœåšçãªããã«ããã¯ãç¹å®ãããã£ãã·ã¥ç¡å¹åæŠç¥ãæé©åããŸããã¢ãã¿ãªã³ã°ã¯ããã£ãã·ã³ã°æŠç¥ã®æå¹æ§ã«é¢ãã貎éãªæŽå¯ãæäŸããŸãã
- ç¡å¹åããžãã¯ã®äžå åïŒ ã³ãŒãã®ä¿å®æ§ãšäžè²«æ§ãä¿é²ããããã«ãç¡å¹åããžãã¯ãåå©çšå¯èœãªé¢æ°ãã¢ãžã¥ãŒã«ã«ã«ãã»ã«åããŸããäžå åãããç¡å¹åã·ã¹ãã ã«ãããæéãšãšãã«ç¡å¹åæŠç¥ã管çããã³æŽæ°ãããããªããŸãã
- ãšããžã±ãŒã¹ãèæ ®ããïŒ ãããã¯ãŒã¯ãšã©ãŒããµãŒããŒã®é害ã忿޿°ãªã©ã®ãšããžã±ãŒã¹ã«ã€ããŠèããŸããã¢ããªã±ãŒã·ã§ã³ãå埩åãç¶æã§ããããã«ããšã©ãŒãã³ããªã³ã°ãšãªãã©ã€ã¡ã«ããºã ãå®è£ ããŸãã
- äžè²«ããããŒã€ã³ã°æŠç¥ã䜿çšããïŒ ãã¹ãŠã®ã¯ãšãªã«å¯ŸããŠãäžè²«ããŠããŒãçæãããããã®ããŒãäžè²«æ§ã®ããäºæž¬å¯èœãªæ¹æ³ã§ç¡å¹åããæ¹æ³ã確ä¿ããŸãã
ã·ããªãªäŸïŒEã³ããŒã¹ã¢ããªã±ãŒã·ã§ã³
ãããã®æŠç¥ãå®éã«ã©ã®ããã«é©çšã§ãããã説æããããã«ãEã³ããŒã¹ã¢ããªã±ãŒã·ã§ã³ãèããŠã¿ãŸãããã
- ååã«ã¿ãã°ïŒ ååã«ã¿ãã°ããŒã¿ã¯æ¯èŒçéçãªã®ã§ãäžçšåºŠã®TTLïŒäŸïŒ1æéïŒãæã€æéããŒã¹ã®æå¹æéæŠç¥ã䜿çšã§ããŸãã
- ååè©³çŽ°ïŒ äŸ¡æ Œã説æãªã©ã®åå詳现ã¯ãããé »ç¹ã«å€æŽãããå¯èœæ§ããããŸããçãTTLïŒäŸïŒ15åïŒãã€ãã³ãããŒã¹ã®ç¡å¹åã䜿çšã§ããŸããååã®äŸ¡æ ŒãæŽæ°ãããå Žåã察å¿ãããã£ãã·ã¥ãšã³ããªã¯ç¡å¹åãããã¹ãã§ãã
- ã·ã§ããã³ã°ã«ãŒãïŒ ã·ã§ããã³ã°ã«ãŒãã®ããŒã¿ã¯éåžžã«åçã§ãŠãŒã¶ãŒåºæã§ããã€ãã³ãããŒã¹ã®ç¡å¹åãäžå¯æ¬ ã§ãããŠãŒã¶ãŒãã«ãŒãã«ååã远å ãåé€ããŸãã¯æŽæ°ãããã³ã«ãã«ãŒãããŒã¿ã®ãã£ãã·ã¥ã¯ç¡å¹åãããã¹ãã§ãã
- åšåº«ã¬ãã«ïŒ åšåº«ã¬ãã«ã¯ãç¹ã«ããŒã¯ã®ã·ã§ããã³ã°ã·ãŒãºã³äžã«é »ç¹ã«å€åããå¯èœæ§ããããŸããåšåº«ã¬ãã«ã倿Žããããã³ã«ãªã¢ã«ã¿ã€ã ã®æŽæ°ãåä¿¡ãããã£ãã·ã¥ãç¡å¹åããããã«SSEãŸãã¯WebSocketã®äœ¿çšãæ€èšããŠãã ããã
- ã«ã¹ã¿ããŒã¬ãã¥ãŒïŒ ã«ã¹ã¿ããŒã¬ãã¥ãŒã¯ããŸãé »ç¹ã«ã¯æŽæ°ãããªããããããŸãããã³ã³ãã³ãã¢ãã¬ãŒã·ã§ã³æã®æåããªã¬ãŒã«å ããŠãããé·ãTTLïŒäŸïŒ24æéïŒã劥åœã§ãããã
çµè«
广çãªãã£ãã·ã¥æå¹æé管çã¯ãããã©ãŒãã³ã¹ãé«ãããŒã¿æŽåæ§ã®ããReact Suspenseã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããã«äžå¯æ¬ ã§ããããŸããŸãªç¡å¹åæŠç¥ãçè§£ãããã¹ããã©ã¯ãã£ã¹ãé©çšããããšã§ããŠãŒã¶ãŒãåžžã«ææ°ã®æ å ±ã«ã¢ã¯ã»ã¹ã§ããããã«ä¿èšŒã§ããŸããã¢ããªã±ãŒã·ã§ã³ã®ç¹å®ã®ããŒãºãæ éã«æ€èšãããããã®ããŒãºã«æãé©ããç¡å¹åæŠç¥ãéžæããŠãã ãããæé©ãªãã£ãã·ã¥æ§æãèŠã€ããããã«ãå®éšãšå埩ãæããªãã§ãã ãããé©åã«èšèšããããã£ãã·ã¥ç¡å¹åæŠç¥ã«ããããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãšReactã¢ããªã±ãŒã·ã§ã³ã®å šäœçãªããã©ãŒãã³ã¹ãå€§å¹ ã«åäžãããããšãã§ããŸãã
ãªãœãŒã¹ã®ç¡å¹åã¯ç¶ç¶çãªããã»ã¹ã§ããããšãå¿ããªãã§ãã ãããã¢ããªã±ãŒã·ã§ã³ãé²åããã«ã€ããŠãæ°ããæ©èœãå€åããããŒã¿ãã¿ãŒã³ã«å¯Ÿå¿ããããã«ç¡å¹åæŠç¥ã調æŽããå¿ èŠããããããããŸãããå¥å šã§ããã©ãŒãã³ã¹ã®é«ããã£ãã·ã¥ãç¶æããããã«ã¯ãç¶ç¶çãªç£èŠãšæé©åãäžå¯æ¬ ã§ãã