Reactã®å®éšçããã¯experimental_useFormStatusãæ¢æ±ãããªã¢ã«ã¿ã€ã ã®ãã©ãŒã ç£èŠã§UXãåäžããã峿ãã£ãŒãããã¯ãæäŸããŸããå®è£ ãšãã¹ããã©ã¯ãã£ã¹ãåŠã³ãŸãããã
React experimental_useFormStatus ãªã¢ã«ã¿ã€ã ãšã³ãžã³ïŒã©ã€ããã©ãŒã ç£èŠ
çŸä»£ã®Webã¯ãã¬ã¹ãã³ã·ãã§çŽæçãªãŠãŒã¶ãŒã€ã³ã¿ãŒãã§ãŒã¹ãæ±ããŠããŸããWebã¢ããªã±ãŒã·ã§ã³ã®åºæ¬çãªæ§æèŠçŽ ã§ãããã©ãŒã ã¯ããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ïŒUXïŒã«çްå¿ã®æ³šæãæãå¿
èŠããããŸããReactã®experimental_useFormStatus
ããã¯ã¯ããã©ãŒã éä¿¡äžã«ãªã¢ã«ã¿ã€ã ã®ãã£ãŒãããã¯ãæäŸããããã®åŒ·åãªã¡ã«ããºã ãæäŸãããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã倧å¹
ã«åäžãããŸãããã®èšäºã§ã¯ããã®å®éšçAPIã®æ©èœã«ã€ããŠæãäžãããã®ãŠãŒã¹ã±ãŒã¹ãå®è£
ã®è©³çްããããŠã°ããŒãã«ãªãªãŒãã£ãšã³ã¹ã«åããé
åçã§æçãªãã©ãŒã ãäœæããããã®ãã¹ããã©ã¯ãã£ã¹ãæ¢ããŸãã
experimental_useFormStatusãšã¯ïŒ
experimental_useFormStatus
ã¯ãReactãµãŒããŒã³ã³ããŒãã³ãã«ãã£ãŠéå§ããããã©ãŒã éä¿¡ã®ã¹ããŒã¿ã¹ã«é¢ããæ
å ±ãæäŸããããã«èšèšãããReactããã¯ã§ããããã¯ãéçºè
ãReactã³ã³ããŒãã³ãããçŽæ¥ãµãŒããŒãµã€ãã®ããžãã¯ãå®è¡ã§ããããã«ãããµãŒããŒã¢ã¯ã·ã§ã³ã«å¯ŸããReactã®ç¶ç¶çãªæ¢æ±ã®äžéšã§ãããã®ããã¯ã¯ãæ¬è³ªçã«ãµãŒããŒã®ãã©ãŒã åŠçç¶æ
ã®ã¯ã©ã€ã¢ã³ããµã€ããã¥ãŒãæäŸããéçºè
ãé«åºŠã«ã€ã³ã¿ã©ã¯ãã£ãã§ã¬ã¹ãã³ã·ããªãã©ãŒã äœéšãæ§ç¯ã§ããããã«ããŸãã
experimental_useFormStatus
ãç»å Žãã以åã¯ããã©ãŒã éä¿¡ã«é¢ãããªã¢ã«ã¿ã€ã ã®æŽæ°ãæäŸããã«ã¯ãè€éãªç¶æ
管çãéåææäœããããŠããŒãã£ã³ã°ç¶æ
ããšã©ãŒç¶æ
ã®æååŠçããã°ãã°äŒŽããŸããããã®ããã¯ã¯ããã©ãŒã éä¿¡ã¹ããŒã¿ã¹ã«ã¢ã¯ã»ã¹ããããã®å®£èšçã§ç°¡æœãªæ¹æ³ãæäŸãããã®ããã»ã¹ãåçåããŸãã
experimental_useFormStatusã䜿çšããäž»ãªã¡ãªãã
- ãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã®åäžïŒ ãã©ãŒã éä¿¡ã®é²æç¶æ³ã«ã€ããŠãŠãŒã¶ãŒã«å³æãã£ãŒãããã¯ãæäŸããäžç¢ºå®æ§ãæžãããå šäœçãªæºè¶³åºŠãåäžãããŸãã
- ãªã¢ã«ã¿ã€ã ã®ãšã©ãŒåŠçïŒ ãã©ãŒã ãã£ãŒã«ãã«ã€ã³ã©ã€ã³ã§ç¹å®ã®ãšã©ãŒã¡ãã»ãŒãžã衚瀺ã§ããããããŠãŒã¶ãŒã¯å ¥åãä¿®æ£ãããããªããŸãã
- ç¶æ 管çã®ç°¡çŽ åïŒ ãã©ãŒã éä¿¡ã¹ããŒã¿ã¹ã«é¢é£ããæåã®ç¶æ 管çãäžèŠã«ãªããã³ãŒãã®è€éãã軜æžãããŸãã
- ã¢ã¯ã»ã·ããªãã£ã®åŒ·åïŒ æ¯æŽæè¡ã«ãã©ãŒã ã®ã¹ããŒã¿ã¹ã«é¢ãããªã¢ã«ã¿ã€ã ã®æŽæ°ãæäŸã§ãããããé害ãæã€ãŠãŒã¶ãŒã®ã¢ã¯ã»ã·ããªãã£ãåäžããŸãã
- ããã°ã¬ãã·ããšã³ãã³ã¹ã¡ã³ãïŒ JavaScriptãç¡å¹ã«ãªã£ãŠããããèªã¿èŸŒã¿ã«å€±æããå Žåã§ããã©ãŒã ã¯æ©èœãç¶ããåºæ¬çãªã¬ãã«ã®æ©èœæ§ãä¿èšŒããŸãã
experimental_useFormStatusã®ä»çµã¿
ãã®ããã¯ã¯ã以äžã®ããããã£ãæã€ãªããžã§ã¯ããè¿ããŸãïŒ
pending
: ãã©ãŒã ã®éä¿¡ãçŸåšé²è¡äžãã©ããã瀺ãããŒã«å€ãdata
: ãã©ãŒã éä¿¡ãæåããåŸã«ãµãŒããŒã¢ã¯ã·ã§ã³ããè¿ãããããŒã¿ãããã«ã¯ç¢ºèªã¡ãã»ãŒãžãæŽæ°ãããããŒã¿ããã®ä»é¢é£æ å ±ãå«ãŸããå ŽåããããŸããerror
: ãã©ãŒã éä¿¡äžã«çºçãããšã©ãŒã®è©³çްãå«ããšã©ãŒãªããžã§ã¯ããaction
: ãã©ãŒã ãéä¿¡ããããšãã«åŒã³åºããããµãŒããŒã¢ã¯ã·ã§ã³é¢æ°ãããã«ãããå®è¡ãããŠããç¹å®ã®ã¢ã¯ã·ã§ã³ã«åºã¥ããŠç°ãªãUIèŠçŽ ãæ¡ä»¶ä»ãã§ã¬ã³ããªã³ã°ã§ããŸãã
å®è·µçãªäŸãšå®è£
experimental_useFormStatus
ãå©çšããç°¡åãªé£çµ¡å
ãã©ãŒã ã®äŸãèããŠã¿ãŸãããïŒ
äŸ1ïŒåºæ¬çãªãåãåãããã©ãŒã
ãŸãããã©ãŒã éä¿¡ãåŠçãããµãŒããŒã¢ã¯ã·ã§ã³ãå®çŸ©ããŸãïŒå¥ã®ãã¡ã€ã«ãäŸïŒ`actions.js`ã«é 眮ããŸãïŒïŒ
"use server";
import { revalidatePath } from 'next/cache';
export async function submitContactForm(prevState: any, formData: FormData) {
const name = formData.get('name');
const email = formData.get('email');
const message = formData.get('message');
if (!name || !email || !message) {
return {
message: 'ãã¹ãŠã®ãã£ãŒã«ããå
¥åããŠãã ããã',
};
}
// ããŒã¿ããŒã¹æäœãAPIåŒã³åºããã·ãã¥ã¬ãŒã
await new Promise((resolve) => setTimeout(resolve, 2000));
try {
// å®éã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ãããŒã¿ãããã¯ãšã³ãã«éä¿¡ããŸã
console.log('ãã©ãŒã ããŒã¿ãéä¿¡ãããŸããïŒ', { name, email, message });
// æåãã·ãã¥ã¬ãŒã
revalidatePath('/'); // ãªãã·ã§ã³ïŒå¿
èŠã«å¿ããŠã«ãŒããã¹ãåæ€èšŒ
return { message: 'ã¡ãã»ãŒãžããããšãããããŸãïŒ' };
} catch (error: any) {
console.error('ãã©ãŒã éä¿¡ãšã©ãŒïŒ', error);
return { message: 'ãã©ãŒã ã®éä¿¡ã«å€±æããŸãããåŸã§ããäžåºŠã詊ããã ããã' };
}
}
次ã«ã`experimental_useFormStatus`ã䜿çšããŠãã©ãŒã ã³ã³ããŒãã³ããå®è£ ããŸãïŒ
'use client';
import { experimental_useFormStatus as useFormStatus } from 'react-dom';
import { submitContactForm } from './actions';
function ContactForm() {
const { pending, data, error } = useFormStatus();
return (
);
}
export default ContactForm;
ãã®äŸã§ã¯ïŒ
useFormStatus
ããã¯ãåŒã³åºããããã©ãŒã ã®éä¿¡ã¹ããŒã¿ã¹ãååŸãããŸããpending
ããããã£ã¯ããã©ãŒã éä¿¡äžã«ãã©ãŒã ã®å ¥åãšéä¿¡ãã¿ã³ãç¡å¹ã«ããããã«äœ¿çšãããŸããããã«ããããŠãŒã¶ãŒããã©ãŒã ãè€æ°åéä¿¡ããã®ãé²ããŸããerror
ããããã£ã¯ããã©ãŒã ã®éä¿¡ã倱æããå Žåã«ãšã©ãŒã¡ãã»ãŒãžã衚瀺ããããã«äœ¿çšãããŸããdata
ããããã£ïŒå ·äœçã«ã¯`data.message`ïŒã¯ããã©ãŒã ãæ£åžžã«éä¿¡ãããåŸã«æåã¡ãã»ãŒãžã衚瀺ããããã«äœ¿çšãããŸãã
äŸ2ïŒããŒãã£ã³ã°ã€ã³ãžã±ãŒã¿ãŒã®è¡šç€º
ãã©ãŒã éä¿¡äžã«ããŒãã£ã³ã°ã€ã³ãžã±ãŒã¿ãŒã衚瀺ããããšã§ããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãããã«åäžãããããšãã§ããŸããããã¯CSSã¢ãã¡ãŒã·ã§ã³ããµãŒãããŒãã£ã®ã©ã€ãã©ãªã䜿çšããŠå®çŸã§ããŸãïŒ
'use client';
import { experimental_useFormStatus as useFormStatus } from 'react-dom';
import { submitContactForm } from './actions';
function ContactForm() {
const { pending, data, error } = useFormStatus();
return (
);
}
export default ContactForm;
CSSïŒäŸïŒå¥ã®CSSãã¡ã€ã«ãstyled-componentså ïŒïŒ
.loading {
display: inline-block;
width: 16px;
height: 16px;
border: 2px solid #fff;
border-radius: 50%;
border-top-color: #0070f3; /* è²ã®äŸ */
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
ãã®äŸã§ã¯ããã©ãŒã ãpending
ç¶æ
ã®ãšãã«éä¿¡ãã¿ã³ã«ç°¡åãªCSSã¢ãã¡ãŒã·ã§ã³ã远å ããŠããŸãã
äŸ3ïŒã€ã³ã©ã€ã³ãšã©ãŒããªããŒã·ã§ã³
ã€ã³ã©ã€ã³ã§ã®ãšã©ãŒããªããŒã·ã§ã³ãæäŸããããšã§ããŠãŒã¶ãŒã¯å
¥åãšã©ãŒãç¹å®ããä¿®æ£ãããããªããŸããerror
ããããã£ã䜿çšããŠã察å¿ãããã©ãŒã ãã£ãŒã«ãã®é£ã«ãšã©ãŒã¡ãã»ãŒãžã衚瀺ã§ããŸãã
'use client';
import { experimental_useFormStatus as useFormStatus } from 'react-dom';
import { submitContactForm } from './actions';
function ContactForm() {
const { pending, data, error } = useFormStatus();
// ã·ãã¥ã¬ãŒããããããªããŒã·ã§ã³ãšã©ãŒïŒå®éã®ããªããŒã·ã§ã³ããžãã¯ã«çœ®ãæããŠãã ããïŒ
const validationErrors = {
name: error?.message?.includes('name') ? 'ååã¯å¿
é ã§ãã' : null,
email: error?.message?.includes('email') ? 'ç¡å¹ãªã¡ãŒã«ã¢ãã¬ã¹ã§ãã' : null,
message: error?.message?.includes('message') ? 'ã¡ãã»ãŒãžã¯å¿
é ã§ãã' : null,
};
return (
);
}
export default ContactForm;
ãã®äŸã§ã¯ãåãåã£ããšã©ãŒã«åºã¥ããŠç°ãªããšã©ãŒã¡ãã»ãŒãžãã·ãã¥ã¬ãŒãããŠããŸããå®éã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ããµãŒããŒã¢ã¯ã·ã§ã³å ã§ããããããæŽç·ŽãããããªããŒã·ã§ã³ããžãã¯ãå®è£ ãããã©ãŒã ãã£ãŒã«ãã«åºã¥ããŠæ§é åããããšã©ãŒæ å ±ãè¿ãããšã«ãªãã§ãããããã®æ§é åãããããŒã¿ã«ãããã¯ã©ã€ã¢ã³ãã³ã³ããŒãã³ãã§ãšã©ãŒãæ£ããå ¥åãã£ãŒã«ãã«ãããã³ã°ãããããªããŸãã
experimental_useFormStatusã䜿çšããããã®ãã¹ããã©ã¯ãã£ã¹
- ãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãæåªå
ã«ïŒ
experimental_useFormStatus
ã䜿çšããäž»ãªç®çã¯ããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãåäžãããããšã§ãããã©ãŒã éä¿¡ã®ã¹ããŒã¿ã¹ã«ã€ããŠãæç¢ºã§ç°¡æœãªãã£ãŒãããã¯ããŠãŒã¶ãŒã«æäŸããããšã«éäžããŠãã ããã - ãšã©ãŒãé©åã«åŠçããïŒ äºæãã¬ãšã©ãŒãé©åã«åŠçããããã®å ç¢ãªãšã©ãŒãã³ããªã³ã°ãå®è£ ããŠãã ãããåé¡ã解決ããã®ã«åœ¹ç«ã€ãšã©ãŒã¡ãã»ãŒãžããŠãŒã¶ãŒã«æäŸããŸãã
- é©åãªããŒãã£ã³ã°ã€ã³ãžã±ãŒã¿ãŒã䜿çšããïŒ ããŒãã£ã³ã°ã€ã³ãžã±ãŒã¿ãŒã䜿çšããŠããã©ãŒã ãéä¿¡äžã§ããããšãèŠèŠçã«äŒããŸããã³ã³ããã¹ããšéä¿¡ããã»ã¹ã®æéã«é©ããããŒãã£ã³ã°ã€ã³ãžã±ãŒã¿ãŒãéžæããŠãã ããã
- éä¿¡äžã¯ãã©ãŒã å ¥åãç¡å¹ã«ããïŒ ãã©ãŒã éä¿¡äžã¯ãã©ãŒã å ¥åãç¡å¹ã«ããŠããŠãŒã¶ãŒããã©ãŒã ãè€æ°åéä¿¡ããã®ãé²ããŸãã
- ã¢ã¯ã»ã·ããªãã£ãèæ ®ããïŒ ãã©ãŒã ãé害ãæã€ãŠãŒã¶ãŒã«ãå©çšå¯èœã§ããããšã確èªããŠãã ãããARIA屿§ã䜿çšããŠãæ¯æŽæè¡ã«ãã©ãŒã ã®ã¹ããŒã¿ã¹ã«é¢ãããªã¢ã«ã¿ã€ã ã®æŽæ°ãæäŸããŸãã
- ãµãŒããŒãµã€ãããªããŒã·ã§ã³ãå®è£ ããïŒ ããŒã¿ã®æŽåæ§ãšã»ãã¥ãªãã£ã確ä¿ããããã«ãåžžã«ãµãŒããŒãµã€ãã§ãã©ãŒã ããŒã¿ãæ€èšŒããŠãã ããã
- ããã°ã¬ãã·ããšã³ãã³ã¹ã¡ã³ãïŒ JavaScriptãç¡å¹ã«ãªã£ãŠããããèªã¿èŸŒã¿ã«å€±æããå Žåã§ããã©ãŒã ãæ©èœããããã«ããŸããJavaScriptãå©çšã§ããªãå Žåã¯ãæšæºã®HTMLãã©ãŒã éä¿¡ã䜿çšããŠåºæ¬çãªãã©ãŒã éä¿¡ãæ©èœããã¹ãã§ãã
- ãµãŒããŒã¢ã¯ã·ã§ã³ãæé©åããïŒ ãµãŒããŒã¢ã¯ã·ã§ã³ãå¹ççã«å®è¡ããããã«æé©åããŸããã¡ã€ã³ã¹ã¬ããããããã¯ããããã©ãŒãã³ã¹ã«æªåœ±é¿ãäžããå¯èœæ§ã®ããé·æéå®è¡ãããæäœã¯é¿ããŠãã ããã
- 泚æããŠäœ¿çšããïŒå®éšçAPIïŒïŒ
experimental_useFormStatus
ã¯å®éšçãªAPIã§ãããå°æ¥ã®ReactãªãªãŒã¹ã§å€æŽãããå¯èœæ§ãããããšã«æ³šæããŠãã ãããæ¬çªç°å¢ã§ã¯æ³šæããŠäœ¿çšããå¿ èŠã«å¿ããŠã³ãŒããé©å¿ãããæºåãããŠãã ããã - åœéåãšå°ååïŒi18n/l10nïŒïŒ ã°ããŒãã«ãªã¢ããªã±ãŒã·ã§ã³ã§ã¯ããã¹ãŠã®ã¡ãã»ãŒãžïŒæåããšã©ãŒãããŒãã£ã³ã°ïŒããç°ãªãèšèªãå°åããµããŒãããããã«é©åã«åœéåããã³å°ååãããŠããããšã確èªããŠãã ããã
ã°ããŒãã«ãªèæ ®äºé ãšã¢ã¯ã»ã·ããªãã£
ã°ããŒãã«ãªãªãŒãã£ãšã³ã¹åãã®ãã©ãŒã ãæ§ç¯ããéã«ã¯ã次ã®ç¹ãèæ ®ããããšãéèŠã§ãïŒ
- åœéåïŒi18nïŒïŒ ã©ãã«ããšã©ãŒã¡ãã»ãŒãžãæåã¡ãã»ãŒãžãå«ããã¹ãŠã®ããã¹ãã¯ãè€æ°ã®èšèªããµããŒãããããã«åœéåãããã¹ãã§ãã
react-intl
ãi18next
ã®ãããªã©ã€ãã©ãªã䜿çšããŠç¿»èš³ã管çããŸãã - å°ååïŒl10nïŒïŒ æ¥ä»ãæ°å€ãé貚ã®ãã©ãŒãããã¯ããŠãŒã¶ãŒã®ãã±ãŒã«ã«åãããŠå°ååãããã¹ãã§ãã
Intl
ãªããžã§ã¯ããdate-fns
ã®ãããªã©ã€ãã©ãªã䜿çšããŠããŒã¿ãé©åã«ãã©ãŒãããããŸãã - å³ããå·ŠïŒRTLïŒãžã®ã¬ã€ã¢ãŠãïŒ ã¢ã©ãã¢èªãããã©ã€èªã®ãããªå³ããå·Šãžã®èšèªããã©ãŒã ã¬ã€ã¢ãŠããæ£ããåŠçã§ããããã«ããŠãã ãããCSSè«çããããã£ãã¬ã€ã¢ãŠãæè¡ã䜿çšããŠãç°ãªãæžåæ¹åã«é©å¿ããæè»ãªã¬ã€ã¢ãŠããäœæããŸãã
- ã¢ã¯ã»ã·ããªãã£ïŒa11yïŒïŒ ã¢ã¯ã»ã·ããªãã£ã¬ã€ãã©ã€ã³ã«åŸãããã©ãŒã ãé害ãæã€äººã ã«ãå©çšå¯èœã§ããããšã確èªããŸããæå³çãªHTMLèŠçŽ ã䜿çšããç»åã«ã¯ä»£æ¿ããã¹ããæäŸãããã©ãŒã ãããŒããŒãã§ã¢ã¯ã»ã¹å¯èœã§ããããšãä¿èšŒããŸããARIA屿§ã䜿çšããŠãæ¯æŽæè¡ã«è¿œå æ å ±ãæäŸããŸãã
- åœéããŒã¿ã®ããªããŒã·ã§ã³ïŒ é»è©±çªå·ãäœæãéµäŸ¿çªå·ãªã©ã®ããŒã¿ãæ€èšŒããéã«ã¯ãåœéçãªãã©ãŒãããããµããŒãããããªããŒã·ã§ã³ã©ã€ãã©ãªã䜿çšããŸãã
- ã¿ã€ã ãŸãŒã³ïŒ æ¥ä»ãšæå»ãåéããéã«ã¯ãã¿ã€ã ãŸãŒã³ã«æ³šæãããŠãŒã¶ãŒãåžæã®ã¿ã€ã ãŸãŒã³ãéžæã§ãããªãã·ã§ã³ãæäŸããŸãã
çµè«
Reactã®experimental_useFormStatus
ããã¯ã¯ãã€ã³ã¿ã©ã¯ãã£ãã§ãŠãŒã¶ãŒãã¬ã³ããªãŒãªãã©ãŒã ãæ§ç¯ããäžã§å€§ããªé²æ©ããããããŸãããã©ãŒã éä¿¡ã¹ããŒã¿ã¹ã«é¢ãããªã¢ã«ã¿ã€ã ã®ãã£ãŒãããã¯ãæäŸããããšã§ãéçºè
ã¯ãŠãŒã¶ãŒã®æºè¶³åºŠãåäžãããäžæºã軜æžããé
åçãªäœéšãåµé ã§ããŸããçŸåšãããã¯å®éšçãªAPIã§ããããã©ãŒã ã®ç¶æ
管çãç°¡çŽ åããUXãåäžããããã®å¯èœæ§ã¯ãæ¢æ±ãã䟡å€ã®ããããŒã«ãšãªã£ãŠããŸããäžçäžã®ãŠãŒã¶ãŒã®ããã«å
æ¬çãªãã©ãŒã ãäœæããããã«ãã°ããŒãã«ãªã¢ã¯ã»ã·ããªãã£ãšåœéåã®ãã¹ããã©ã¯ãã£ã¹ãèæ
®ããããšãå¿ããªãã§ãã ãããReactãé²åãç¶ããã«ã€ããŠãexperimental_useFormStatus
ã®ãããªããŒã«ã¯ãçŸä»£çã§ã¬ã¹ãã³ã·ããªWebã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããã«ãŸããŸãéèŠã«ãªãã§ãããã