React SuspenseãªãœãŒã¹é£æºïŒãã«ããªãœãŒã¹ã®ããŒã管çããã¹ã¿ãŒãã | MLOG | MLOGæ¥æ¬èª
Suspenseã䜿çšããŠReactã¢ããªã±ãŒã·ã§ã³ã§ã®ãã«ããªãœãŒã¹ã®ããŒãã广çã«ç®¡çããããã¹ã ãŒãºãªãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã®ããã«äŸåé¢ä¿ã調æŽããæ¹æ³ãåŠã³ãŸãã
React SuspenseãªãœãŒã¹é£æºïŒãã«ããªãœãŒã¹ã®ããŒã管çããã¹ã¿ãŒãã
React Suspenseã¯ãéåæåŠçãåŠçããã¢ããªã±ãŒã·ã§ã³ã§ã®ããŒãã£ã³ã°ç¶æ
ã管çããããã®åŒ·åãªã¡ã«ããºã ãæäŸããŸããç°¡åãªããŒã¿ãã§ããã®ã·ããªãªã¯æ¯èŒçç°¡åã§ãããäºãã«äŸåé¢ä¿ãæã€è€æ°ã®ãªãœãŒã¹ãæ±ãå Žåã¯ãããè€éã«ãªããŸãããã®ããã°èšäºã§ã¯ãReact Suspenseã䜿çšãããªãœãŒã¹é£æºã«ã€ããŠæ·±ãæãäžããããã¹ã ãŒãºã§å¿çæ§ã®é«ããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã®ããã«ããã«ããªãœãŒã¹ã®ããŒãã广çã«ç®¡çããæ¹æ³ã説æããŸãã
ãã«ããªãœãŒã¹ã®ããŒãã®èª²é¡ãçè§£ãã
å€ãã®å®éã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ãã³ã³ããŒãã³ãã¯å€ãã®å Žåãè€æ°ã®ãœãŒã¹ããã®ããŒã¿ã«äŸåããŸããããšãã°ããŠãŒã¶ãŒãããã¡ã€ã«ããŒãžã§ã¯ããŠãŒã¶ãŒã®è©³çްãæè¿ã®ã¢ã¯ãã£ããã£ãããã³é¢é£ããæçš¿ããã§ããããå¿
èŠããããŸãããããã®ãªãœãŒã¹ãåå¥ã«ããŒããããšãããã€ãã®åé¡ãçºçããå¯èœæ§ããããŸãã
- ãŠã©ãŒã¿ãŒãã©ãŒã«ãªã¯ãšã¹ãïŒåãªãœãŒã¹ãé çªã«ããŒãããããããããŒãæéãå¢å ããŸãã
- UIç¶æ
ã®äžæŽåïŒUIã®ç°ãªãéšåãç°ãªãã¿ã€ãã³ã°ã§ããŒããããäžå¿«ãªãšã¯ã¹ããªãšã³ã¹ãçããå¯èœæ§ããããŸãã
- è€éãªç¶æ
管çïŒè€æ°ã®ããŒãã£ã³ã°ç¶æ
ãšãšã©ãŒæ¡ä»¶ã®åŠçãç
©éã«ãªããŸãã
- äžååãªãšã©ãŒåŠçïŒè€æ°ã®ãªãœãŒã¹ã«ããããšã©ãŒåŠçã®èª¿æŽã¯é£ããå ŽåããããŸãã
Suspenseã¯ããªãœãŒã¹é£æºã®æŠç¥ãšçµã¿åãããããšã§ããããã®èª²é¡ã«åãçµãããã®ã¯ãªãŒã³ã§å¹ççãªæ¹æ³ãæäŸããŸãã
ã³ã¢ã³ã³ã»ããïŒSuspenseãšãªãœãŒã¹
飿ºæŠç¥ã«å
¥ãåã«ãåºæ¬çãªã³ã³ã»ããã埩ç¿ããŸãããã
Suspense
Suspenseã¯ãReactã³ã³ããŒãã³ãã§ãããããŒã¿ãã§ãããªã©ã®éåææäœãå®äºãããŸã§ãã³ã³ããŒãã³ãããªãŒã®äžéšããäžæåæ¢ãã§ããŸããæäœãé²è¡äžã®éã¯ããã©ãŒã«ããã¯UIïŒããŒãã£ã³ã°ã¹ãããŒãªã©ïŒã衚瀺ãããŸããSuspenseã¯ãããŒãã£ã³ã°ç¶æ
ã®ç®¡çãç°¡çŽ åããå
šäœçãªãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãåäžãããŸãã
äŸïŒ
import React, { Suspense } from 'react';
function MyComponent() {
return (
Loading... }>
);
}
ãªãœãŒã¹
ãªãœãŒã¹ã¯ãéåææäœãã«ãã»ã«åããããŒã¿ã«ã¢ã¯ã»ã¹ããããSuspenseããã£ããã§ããPromiseãã¹ããŒãããããæ¹æ³ãæäŸãããªããžã§ã¯ãã§ããäžè¬çãªãªãœãŒã¹ã«ã¯ãPromiseãè¿ãããŒã¿ãã§ãã颿°ãå«ãŸããŸãã
äŸïŒåçŽãªfetchã©ãããŒã䜿çšïŒïŒ
const fetchData = (url) => {
let status = 'pending';
let result;
let suspender = fetch(url)
.then(
(res) => res.json(),
(err) => {
status = 'error';
result = err;
}
)
.then(
(res) => {
status = 'success';
result = res;
}
);
return {
read() {
if (status === 'pending') {
throw suspender;
} else if (status === 'error') {
throw result;
}
return result;
},
};
};
export default fetchData;
ãã«ããªãœãŒã¹é£æºã®æŠç¥
Suspenseã䜿çšããŠè€æ°ã®ãªãœãŒã¹ã广çã«ç®¡çããããã®æŠç¥ãããã€ã玹ä»ããŸãã
1. `Promise.all`ã䜿çšãã䞊åããŒã
æãç°¡åãªã¢ãããŒãã¯ããã¹ãŠã®ãªãœãŒã¹ã䞊è¡ããŠããŒããã`Promise.all`ã䜿çšããŠãã³ã³ããŒãã³ããã¬ã³ããªã³ã°ããåã«ãã¹ãŠã®Promiseã解決ãããã®ãåŸ
ã€ããšã§ããããã¯ããªãœãŒã¹ãç¬ç«ããŠãããäºãã«äŸåé¢ä¿ããªãå Žåã«é©ããŠããŸãã
äŸïŒ
import React, { Suspense } from 'react';
import fetchData from './fetchData';
const userResource = fetchData('/api/user');
const postsResource = fetchData('/api/posts');
const commentsResource = fetchData('/api/comments');
function UserProfile() {
const user = userResource.read();
const posts = postsResource.read();
const comments = commentsResource.read();
return (
{user.name}
{user.bio}
Posts
{posts.map((post) => (
- {post.title}
))}
Comments
{comments.map((comment) => (
- {comment.text}
))}
);
}
function App() {
return (
Loading user profile... }>
);
}
export default App;
å©ç¹ïŒ
- å®è£
ãç°¡åã
- 䞊åããŒããæå€§åããå
šäœçãªããŒãæéãççž®ããŸãã
çæïŒ
- ãªãœãŒã¹ã«äŸåé¢ä¿ãããå Žåã¯é©ããŠããŸããã
- äžéšã®ãªãœãŒã¹ãå®éã«å¿
èŠãªãå ŽåãäžèŠãªãªã¯ãšã¹ããçºçããå¯èœæ§ããããŸãã
2. äŸåé¢ä¿ã䜿çšããé æ¬¡ããŒã
ãªãœãŒã¹ãçžäºã«äŸåããŠããå Žåã¯ãããããé çªã«ããŒãããå¿
èŠããããŸããSuspenseã䜿çšãããšãäŸåãªãœãŒã¹ããã§ããããã³ã³ããŒãã³ãããã¹ãããããšã§ããã®ãããŒã調æŽã§ããŸãã
äŸïŒæåã«ãŠãŒã¶ãŒããŒã¿ãããŒãããæ¬¡ã«ãŠãŒã¶ãŒIDã䜿çšããŠæçš¿ããã§ããããŸãã
import React, { Suspense } from 'react';
import fetchData from './fetchData';
const userResource = fetchData('/api/user');
function UserPosts({ userId }) {
const postsResource = fetchData(`/api/posts?userId=${userId}`);
const posts = postsResource.read();
return (
{posts.map((post) => (
- {post.title}
))}
);
}
function UserProfile() {
const user = userResource.read();
return (
{user.name}
{user.bio}
Posts
Loading posts... }>
);
}
function App() {
return (
Loading user profile...}>
);
}
export default App;
å©ç¹ïŒ
- äŸåé¢ä¿ãé©åã«åŠçããŸãã
- äŸåãªãœãŒã¹ã«å¯ŸããäžèŠãªãªã¯ãšã¹ããåé¿ããŸãã
çæïŒ
- é æ¬¡ããŒãã®ãããå
šäœçãªããŒãæéãå¢å ããå¯èœæ§ããããŸãã
- äŸåé¢ä¿ã管çããã«ã¯ãæ
éãªã³ã³ããŒãã³ãæ§é ãå¿
èŠã§ãã
3. 䞊åããŒããšé 次ããŒãã®çµã¿åãã
å€ãã®å Žåãããã©ãŒãã³ã¹ãæé©åããããã«ã䞊åããŒããšé 次ããŒãã®äž¡æ¹ãçµã¿åãããããšãã§ããŸããç¬ç«ãããªãœãŒã¹ã䞊è¡ããŠããŒãããç¬ç«ãããªãœãŒã¹ãããŒããããåŸãäŸåãªãœãŒã¹ãé çªã«ããŒãããŸãã
äŸïŒãŠãŒã¶ãŒããŒã¿ãšæè¿ã®ã¢ã¯ãã£ããã£ã䞊è¡ããŠããŒãããŸããæ¬¡ã«ããŠãŒã¶ãŒããŒã¿ã®ããŒãåŸããŠãŒã¶ãŒã®æçš¿ããã§ããããŸãã
import React, { Suspense } from 'react';
import fetchData from './fetchData';
const userResource = fetchData('/api/user');
const activityResource = fetchData('/api/activity');
function UserPosts({ userId }) {
const postsResource = fetchData(`/api/posts?userId=${userId}`);
const posts = postsResource.read();
return (
{posts.map((post) => (
- {post.title}
))}
);
}
function UserProfile() {
const user = userResource.read();
const activity = activityResource.read();
return (
{user.name}
{user.bio}
Last activity: {activity.date}
Posts
Loading posts... }>
);
}
function App() {
return (
Loading user profile...}>
);
}
export default App;
ãã®äŸã§ã¯ã`userResource`ãš`activityResource`ã¯äžŠè¡ããŠãã§ãããããŸãããŠãŒã¶ãŒããŒã¿ãå©çšå¯èœã«ãªããšã`UserPosts`ã³ã³ããŒãã³ããã¬ã³ããªã³ã°ããããŠãŒã¶ãŒã®æçš¿ã®ãã§ãããããªã¬ãŒãããŸãã
å©ç¹ïŒ
- 䞊åããŒããšé 次ããŒããçµã¿åãããããšã§ãããŒãæéãæé©åããŸãã
- äŸåé¢ä¿ã®ç®¡çã«æè»æ§ãæäŸããŸãã
çæïŒ
- ç¬ç«ãããªãœãŒã¹ãšäŸåãªãœãŒã¹ãç¹å®ããã«ã¯ãæ
éãªèšç»ãå¿
èŠã§ãã
- åçŽãªäžŠåãŸãã¯é 次ããŒããããå®è£
ãè€éã«ãªãå¯èœæ§ããããŸãã
4. React Contextã䜿çšãããªãœãŒã¹ã®å
±æ
React Contextã䜿çšããŠãã³ã³ããŒãã³ãéã§ãªãœãŒã¹ãå
±æããåãããŒã¿ãè€æ°ååãã§ããããããšãåé¿ã§ããŸããããã¯ãè€æ°ã®ã³ã³ããŒãã³ããåããªãœãŒã¹ã«ã¢ã¯ã»ã¹ããå¿
èŠãããå Žåã«ç¹ã«äŸ¿å©ã§ãã
äŸïŒ
import React, { createContext, useContext, Suspense } from 'react';
import fetchData from './fetchData';
const UserContext = createContext(null);
function UserProvider({ children }) {
const userResource = fetchData('/api/user');
return (
{children}
);
}
function UserProfile() {
const userResource = useContext(UserContext);
const user = userResource.read();
return (
);
}
function UserAvatar() {
const userResource = useContext(UserContext);
const user = userResource.read();
return (
);
}
function App() {
return (
Loading user profile... }>
);
}
export default App;
ãã®äŸã§ã¯ã`UserProvider`ã¯ãŠãŒã¶ãŒããŒã¿ããã§ãããã`UserContext`ãä»ããŠãã¹ãŠã®åã«æäŸããŸãã`UserProfile`ã³ã³ããŒãã³ããš`UserAvatar`ã³ã³ããŒãã³ãã®äž¡æ¹ããåããŠãŒã¶ãŒããŒã¿ãåãã§ããããã«ã¢ã¯ã»ã¹ã§ããŸãã
å©ç¹ïŒ
- åé·ãªããŒã¿ãã§ãããåé¿ããŸãã
- ã³ã³ããŒãã³ãéã®ããŒã¿å
±æãç°¡çŽ åããŸãã
çæïŒ
- ã³ã³ããã¹ããããã€ããŒã®æ
éãªç®¡çãå¿
èŠã§ãã
- ã³ã³ããã¹ããäžéšã®ã³ã³ããŒãã³ãã§å¿
èŠãªä»¥äžã®ããŒã¿ãæäŸããå Žåãéå°ãªãã§ãããçºçããå¯èœæ§ããããŸãã
5. å
ç¢ãªãšã©ãŒåŠçã®ããã®ãšã©ãŒå¢ç
Suspenseã¯ãããŒã¿ãã§ãããŸãã¯ã¬ã³ããªã³ã°äžã«çºçãããšã©ãŒãåŠçããããã«ããšã©ãŒå¢çãšããŸã飿ºããŸãããšã©ãŒå¢çã¯ãåã³ã³ããŒãã³ãããªãŒå
ã®JavaScriptãšã©ãŒããã£ãããããããã®ãšã©ãŒããã°ã«èšé²ããã³ã³ããŒãã³ãããªãŒå
šäœãã¯ã©ãã·ã¥ããã代ããã«ãã©ãŒã«ããã¯UIã衚瀺ããReactã³ã³ããŒãã³ãã§ãã
äŸïŒ
import React, { Suspense } from 'react';
import fetchData from './fetchData';
import ErrorBoundary from './ErrorBoundary';
const userResource = fetchData('/api/user');
function UserProfile() {
const user = userResource.read();
return (
);
}
function App() {
return (
Something went wrong! }>
Loading user profile...}>
);
}
export default App;
ãã®äŸã§ã¯ã`ErrorBoundary`ã¯ã`UserProfile`ã³ã³ããŒãã³ãã®ã¬ã³ããªã³ã°äžãŸãã¯ãŠãŒã¶ãŒããŒã¿ã®ãã§ããäžã«çºçãããšã©ãŒããã£ããããŸãããšã©ãŒãçºçããå Žåããã©ãŒã«ããã¯UIã衚瀺ãããã¢ããªã±ãŒã·ã§ã³å
šäœã®ã¯ã©ãã·ã¥ã鲿¢ãããŸãã
å©ç¹ïŒ
- å
ç¢ãªãšã©ãŒåŠçãæäŸããŸãã
- ã¢ããªã±ãŒã·ã§ã³ã®ã¯ã©ãã·ã¥ãé²ããŸãã
- æçãªãšã©ãŒã¡ãã»ãŒãžã衚瀺ããããšã§ããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãåäžãããŸãã
çæïŒ
- ãšã©ãŒå¢çã³ã³ããŒãã³ãã®å®è£
ãå¿
èŠã§ãã
- ã³ã³ããŒãã³ãããªãŒã«è€éãã远å ããå¯èœæ§ããããŸãã
ã°ããŒãã«ãªãŒãã£ãšã³ã¹ã®ããã®å®è·µçãªèæ
®äºé
ã°ããŒãã«ãªãŒãã£ãšã³ã¹åãã®Reactã¢ããªã±ãŒã·ã§ã³ãéçºããå Žåã¯ã以äžãèæ
®ããŠãã ããã
- ããŒã¿ã®ããŒã«ã©ã€ãºïŒããŒã¿ããŠãŒã¶ãŒã®èšèªãšå°åã«åºã¥ããŠããŒã«ã©ã€ãºãããŠããããšã確èªããŸããåœéåïŒi18nïŒã©ã€ãã©ãªã䜿çšããŠãæ¥ä»ãæ°å€ãé貚ãé©åã«ãã©ãŒãããããŸããããšãã°ãéèã¢ããªã±ãŒã·ã§ã³ã§ã¯ããŠãŒã¶ãŒã®å Žæã«åºã¥ããŠé貚èšå·ïŒUSDãEURãJPYãªã©ïŒã衚瀺ããå¿
èŠããããŸãã
- APIãšã³ããã€ã³ãïŒå°ååºæã®APIãšã³ããã€ã³ããŸãã¯ã³ã³ãã³ãããªããªãŒãããã¯ãŒã¯ïŒCDNïŒã䜿çšããŠãã¬ã€ãã³ã·ãççž®ããäžçäžã®ãŠãŒã¶ãŒã®ããã©ãŒãã³ã¹ãåäžãããŸããããšãã°ããœãŒã·ã£ã«ã¡ãã£ã¢ãã©ãããã©ãŒã ã§ã¯ãç°ãªãå°åããã³ã³ãã³ãããã§ããããããã«ç°ãªãAPIãšã³ããã€ã³ãã䜿çšããå ŽåããããŸãã
- ãšã©ãŒã¡ãã»ãŒãžïŒãŠãŒã¶ãŒã®èšèªã§æç¢ºã§ãããããããšã©ãŒã¡ãã»ãŒãžãæäŸããŸããi18nã©ã€ãã©ãªã䜿çšããŠããšã©ãŒã¡ãã»ãŒãžãåçã«ç¿»èš³ããŸãã
- ã¢ã¯ã»ã·ããªãã£ïŒã¢ã¯ã»ã·ããªãã£ã¬ã€ãã©ã€ã³ïŒWCAGïŒã«åŸããã¢ããªã±ãŒã·ã§ã³ãé害ã®ãããŠãŒã¶ãŒã«ãšã£ãŠã¢ã¯ã»ã¹å¯èœã§ããããšã確èªããŸããç»åã®ä»£æ¿ããã¹ããæäŸããã»ãã³ãã£ãã¯HTMLã䜿çšããã¢ããªã±ãŒã·ã§ã³ãããŒããŒãã§ããã²ãŒãå¯èœã§ããããšã確èªããŸãã
- ã¿ã€ã ãŸãŒã³ïŒæ¥ä»ãšæå»ã衚瀺ãããšãã¯ãã¿ã€ã ãŸãŒã³ãæ£ããåŠçããŸãã`moment-timezone`ã®ãããªã©ã€ãã©ãªã䜿çšããŠãæå»ããŠãŒã¶ãŒã®ããŒã«ã«ã¿ã€ã ãŸãŒã³ã«å€æããŸããããšãã°ãã€ãã³ãã®æå»ã衚瀺ããå Žåã¯ããŠãŒã¶ãŒã®ããŒã«ã«æéã«å€æããŠãæ£ããæå»ã衚瀺ãããããã«ããŸãã
å®è·µçãªæŽå¯ãšãã¹ããã©ã¯ãã£ã¹
React Suspenseã䜿çšããŠãã«ããªãœãŒã¹ã®ããŒãã管çããããã®å®è·µçãªæŽå¯ãšãã¹ããã©ã¯ãã£ã¹ãããã€ã玹ä»ããŸãã
- äŸåé¢ä¿ã®ç¹å®ïŒã³ã³ããŒãã³ãããªãŒãæ³šææ·±ãåæãããªãœãŒã¹éã®äŸåé¢ä¿ãç¹å®ããŸãã
- é©åãªæŠç¥ã®éžæïŒäŸåé¢ä¿ãšããã©ãŒãã³ã¹èŠä»¶ã«åºã¥ããŠãé©åãªããŒãæŠç¥ïŒäžŠåãé æ¬¡ããŸãã¯çµã¿åããïŒãéžæããŸãã
- React Contextã®äœ¿çšïŒReact Contextã䜿çšããŠã³ã³ããŒãã³ãéã§ãªãœãŒã¹ãå
±æããåé·ãªããŒã¿ãã§ãããåé¿ããŸãã
- ãšã©ãŒå¢çã®å®è£
ïŒã³ã³ããŒãã³ãããšã©ãŒå¢çã§ã©ããããŠããšã©ãŒãé©åã«åŠçããŸãã
- ããã©ãŒãã³ã¹ã®æé©åïŒã³ãŒãåå²ãšé
å»¶ããŒãã䜿çšããŠãã¢ããªã±ãŒã·ã§ã³ã®åæããŒãæéãççž®ããŸãã
- ããã©ãŒãã³ã¹ã®ç£èŠïŒãã©ãŠã¶ã®éçºè
ããŒã«ãšããã©ãŒãã³ã¹ç£èŠããŒã«ã䜿çšããŠãããã©ãŒãã³ã¹ã®ããã«ããã¯ãç¹å®ããŠå¯ŸåŠããŸãã
- 培åºçãªãã¹ãïŒããŸããŸãªãããã¯ãŒã¯æ¡ä»¶ãšãšã©ãŒã·ããªãªã§ã¢ããªã±ãŒã·ã§ã³ã培åºçã«ãã¹ãããŠãã¢ããªã±ãŒã·ã§ã³ãæåŸ
ã©ããã«åäœããããšã確èªããŸãã
- ããŒã¿ã®ãã£ãã·ã¥ïŒã¯ã©ã€ã¢ã³ãåŽã®ãã£ãã·ã¥ãå®è£
ããŠãAPIãªã¯ãšã¹ãã®æ°ãæžãããããã©ãŒãã³ã¹ãåäžãããŸãã`swr`ã`react-query`ã®ãããªã©ã€ãã©ãªã¯ãããŒã¿ã®ãã£ãã·ã¥ã«åœ¹ç«ã¡ãŸãã
- ãµãŒããŒãµã€ãã¬ã³ããªã³ã°ïŒSSRïŒã®æ€èšïŒSEOãšåæããŒãæéãæ¹åããããã«ããµãŒããŒãµã€ãã¬ã³ããªã³ã°ã®äœ¿çšãæ€èšããŠãã ããã
çµè«
React Suspenseã¯ãéåææäœã管çããã¢ããªã±ãŒã·ã§ã³ã®ãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãåäžãããããã®åŒ·åã§æè»ãªã¡ã«ããºã ãæäŸããŸããSuspenseãšãªãœãŒã¹ã®ã³ã¢ã³ã³ã»ãããçè§£ãããã®ããã°èšäºã§æŠèª¬ãããŠããæŠç¥ãé©çšããããšã§ããã«ããªãœãŒã¹ã®ããŒãã广çã«ç®¡çããã°ããŒãã«ãªãŒãã£ãšã³ã¹åãã®ããå¿çæ§ãé«ãå
ç¢ãªReactã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã§ããŸããäžçäžã®ãŠãŒã¶ãŒåãã«ã¢ããªã±ãŒã·ã§ã³ãéçºããéã¯ãåœéåãã¢ã¯ã»ã·ããªãã£ãããã³ããã©ãŒãã³ã¹ã®æé©åãèæ
®ããããšãå¿ããªãã§ãã ããããããã®ãã¹ããã©ã¯ãã£ã¹ã«åŸãããšã§ãæ©èœçã§ããã ãã§ãªãããŠãŒã¶ãŒãã¬ã³ããªãŒã§èª°ã§ãã¢ã¯ã»ã¹ã§ããã¢ããªã±ãŒã·ã§ã³ãäœæã§ããŸãã