Reactã®experimental_useFormStateããã¯ã掻çšãããã©ãŒã 管çããšã©ãŒåŠçãUXãåäžãããæ¹æ³ãæ¢ããŸããå®è·µçãªäŸãå«ãå æ¬çãªã¬ã€ãã§ãã
React experimental_useFormState: ã¢ãã³ã¢ããªã±ãŒã·ã§ã³ã«ããã匷åããããã©ãŒã 管ç
ãã©ãŒã 管çã¯ãã€ã³ã¿ã©ã¯ãã£ãã§ãŠãŒã¶ãŒãã¬ã³ããªãŒãªWebã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããäžã§éåžžã«éèŠãªåŽé¢ã§ããReactã¯ãã³ã³ããŒãã³ãããŒã¹ã®ã¢ãŒããã¯ãã£ã«ããããã©ãŒã ãæ±ãããã€ãã®æ¹æ³ãæäŸããŠããŸãããµãŒããŒã¢ã¯ã·ã§ã³ã®å°å
¥ãšãããã«ç¶ãexperimental_useFormStateã®ãããªæ©èœåŒ·åã¯ãç¹ã«ãµãŒããŒãµã€ãã®ããžãã¯ãšé£æºããéã®ãã©ãŒã ãã³ããªã³ã°ã«å¯Ÿããéçºè
ã®ã¢ãããŒãã«é©åœããããããŠããŸãããã®å®éšçãªããã¯ã¯ãReactãé²è¡äžã®ãµãŒããŒã³ã³ããŒãã³ããšã¢ã¯ã·ã§ã³ã®æ¢æ±ã®äžéšã§ããããã©ãŒã ã®ç¶æ
管çãšãšã©ãŒãã³ããªã³ã°ãããå¹ççãã€åççã«è¡ãã¢ãããŒããæäŸããŸãã
experimental_useFormStateãšã¯ïŒ
experimental_useFormStateã¯ãç¹ã«ãµãŒããŒã¢ã¯ã·ã§ã³ãšé£æºããã·ããªãªã«ãããŠããã©ãŒã 管çãç°¡çŽ åããããã«èšèšãããReactããã¯ã§ããã¯ã©ã€ã¢ã³ããšãµãŒããŒéã§ãã©ãŒã ã®ç¶æ
ãæž¡ãã¡ã«ããºã ãæäŸããããã·ãŒã ã¬ã¹ãªãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãšæ¹åããããšã©ãŒãã³ããªã³ã°ãå¯èœã«ããŸããReactãµãŒããŒã³ã³ããŒãã³ãããã³ãµãŒããŒã¢ã¯ã·ã§ã³ãšçŽæ¥çµ±åãããå¹ççãªããŒã¿ååŸãšå€æŽãå¯èœã«ããŸãã
詳现ã«å ¥ãåã«ããã®ããã¯ã¯çŸåšå®éšçãªãã®ã§ããããšã«æ³šæããããšãéèŠã§ããããã¯ãAPIãå°æ¥ã®ãªãªãŒã¹ã§å€æŽãããå¯èœæ§ãããããšãæå³ããŸãããããã£ãŠãæ¬çªç°å¢ã§ã®äœ¿çšã¯æ éã«è¡ããææ°ã®Reactããã¥ã¡ã³ãã§æ å ±ã確èªãç¶ããããšããå§ãããŸãã
ãªãexperimental_useFormStateã䜿çšããã®ãïŒ
Reactã«ãããåŸæ¥ã®ãã©ãŒã 管çã¯ãuseStateã®ãããªããã¯ãFormikãReact Hook Formã®ãããªã©ã€ãã©ãªã䜿çšããŠããã©ãŒã ã®ç¶æ
ãããŒã«ã«ã§ç®¡çããããšãå€ãã§ãããããã®ã¢ãããŒãã¯ã¯ã©ã€ã¢ã³ããµã€ãã®ããªããŒã·ã§ã³ãåçŽãªãã©ãŒã æäœã«ã¯å¹æçã§ãããããŒã¿éä¿¡ããšã©ãŒãã³ããªã³ã°ãšãã£ããµãŒããŒãµã€ãã®æäœãæ±ãéã«ã¯ç
©éã«ãªãããšããããŸãã以äžã«experimental_useFormStateãæäŸããããã€ãã®å©ç¹ãæããŸãïŒ
- ãµãŒããŒã¢ã¯ã·ã§ã³çµ±åã®ç°¡çŽ åïŒ ãã®ããã¯ã¯ããã©ãŒã ãšãµãŒããŒã¢ã¯ã·ã§ã³ã®æ¥ç¶ãå€§å¹ ã«å®¹æã«ããŸãããµãŒããŒãžã®ããŒã¿éä¿¡ãããŒãã£ã³ã°ç¶æ ã®ç®¡çããµãŒããŒãµã€ãã®ãšã©ãŒè¡šç€ºãšãã£ãè€éãªåŠçããã³ããªã³ã°ããŸãã
- ãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã®åäžïŒ ã¯ã©ã€ã¢ã³ããšãµãŒããŒéã§ãã©ãŒã ã®ç¶æ
ãæž¡ãããšã«ããã
experimental_useFormStateã¯ããå¿çæ§ãé«ãã€ã³ã¿ã©ã¯ãã£ããªãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãå¯èœã«ããŸããäŸãã°ããã©ãŒã ããµãŒããŒã§åŠçãããŠããéã«ããŠãŒã¶ãŒã«å³åº§ã«ãã£ãŒãããã¯ãæäŸã§ããŸãã - äžå åããããšã©ãŒãã³ããªã³ã°ïŒ ãã®ããã¯ã¯ãã¯ã©ã€ã¢ã³ããšãµãŒããŒã®äž¡æ¹ã§ãã©ãŒã ã®ããªããŒã·ã§ã³ãšã©ãŒãåŠçããããã®äžå çãªã¡ã«ããºã ãæäŸããŸããããã«ããããšã©ãŒè¡šç€ºãç°¡çŽ åãããäžè²«ãããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãä¿èšŒãããŸãã
- ããã°ã¬ãã·ããšã³ãã³ã¹ã¡ã³ãïŒ ãµãŒããŒã¢ã¯ã·ã§ã³ã
experimental_useFormStateãšçµã¿åãããŠäœ¿çšããããšã§ãããã°ã¬ãã·ããšã³ãã³ã¹ã¡ã³ãããµããŒããããŸããJavaScriptãç¡å¹ã«ãªã£ãŠããŠããã©ãŒã ãæ©èœãããã¹ãŠã®ãŠãŒã¶ãŒã«åºæ¬çãªäœéšãæäŸããŸãã - ãã€ã©ãŒãã¬ãŒãã®åæžïŒ åŸæ¥ã®ãã©ãŒã 管çæè¡ãšæ¯èŒããŠã
experimental_useFormStateã¯å¿ èŠãªãã€ã©ãŒãã¬ãŒãã³ãŒãã®éãåæžããã³ã³ããŒãã³ããããã¯ãªãŒã³ã§ä¿å®ããããããŸãã
experimental_useFormStateã®äœ¿ãæ¹
experimental_useFormStateã䜿çšããã«ã¯ããŸããµãŒããŒã¢ã¯ã·ã§ã³ããµããŒãããReactã®ããŒãžã§ã³ïŒReact 18以éïŒã䜿çšããŠããããšã確èªããå¿
èŠããããŸãããŸããReactã®èšå®ã§å®éšçãªæ©èœãæå¹ã«ããå¿
èŠããããŸããããã«ã¯éåžžããã³ãã©ïŒäŸïŒWebpack, ParcelïŒãèšå®ããŠå®éšçæ©èœãæå¹ã«ããããšãå«ãŸããŸãã
以äžã«experimental_useFormStateã®åºæ¬çãªäœ¿çšäŸã瀺ããŸãïŒ
äŸïŒã·ã³ãã«ãªã³ã³ã¿ã¯ããã©ãŒã
ååãã¡ãŒã«ã¢ãã¬ã¹ãã¡ãã»ãŒãžã®ãã£ãŒã«ããæã€ã·ã³ãã«ãªã³ã³ã¿ã¯ããã©ãŒã ãäœæããŸããããexperimental_useFormStateã䜿çšããŠãã©ãŒã ã®éä¿¡ãåŠçããçºçãããšã©ãŒã衚瀺ããŸãã
1. ãµãŒããŒã¢ã¯ã·ã§ã³ãå®çŸ©ããïŒ
ãŸãããã©ãŒã ã®éä¿¡ãåŠçãããµãŒããŒã¢ã¯ã·ã§ã³ãå®çŸ©ããå¿ èŠããããŸãããã®ã¢ã¯ã·ã§ã³ã¯ãã©ãŒã ããŒã¿ãåãåããå¿ èŠãªãµãŒããŒãµã€ãã®ããªããŒã·ã§ã³ãšåŠçïŒäŸïŒã¡ãŒã«ã®éä¿¡ïŒãå®è¡ããŸãã
// server-actions.js
'use server';
import { experimental_useFormState as useFormState } from 'react';
async function submitForm(prevState, formData) {
// ãµãŒããŒãµã€ãããªããŒã·ã§ã³ãã·ãã¥ã¬ãŒã
const name = formData.get('name');
const email = formData.get('email');
const message = formData.get('message');
if (!name) {
return { error: 'ååã¯å¿
é ã§ã' };
}
if (!email) {
return { error: 'ã¡ãŒã«ã¢ãã¬ã¹ã¯å¿
é ã§ã' };
}
if (!message) {
return { error: 'ã¡ãã»ãŒãžã¯å¿
é ã§ã' };
}
// ã¡ãŒã«ã®éä¿¡ãã·ãã¥ã¬ãŒã
try {
await new Promise(resolve => setTimeout(resolve, 1000)); // ãããã¯ãŒã¯é
å»¶ãã·ãã¥ã¬ãŒã
console.log('ãã©ãŒã ãæ£åžžã«éä¿¡ãããŸããïŒ');
return { success: true, message: 'ã¡ãã»ãŒãžããããšãããããŸãïŒ' };
} catch (error) {
console.error('ã¡ãŒã«éä¿¡ãšã©ãŒ:', error);
return { error: 'ã¡ãã»ãŒãžã®éä¿¡ã«å€±æããŸãããããäžåºŠã詊ããã ããã' };
}
}
export default submitForm;
2. Reactã³ã³ããŒãã³ããäœæããïŒ
次ã«ããã©ãŒã ãã¬ã³ããªã³ã°ããexperimental_useFormStateã䜿çšããŠãã©ãŒã ã®ç¶æ
ã管çããReactã³ã³ããŒãã³ããäœæããŸãããã
// ContactForm.jsx
'use client';
import { experimental_useFormState as useFormState } from 'react';
import submitForm from './server-actions';
function ContactForm() {
const [state, formAction] = useFormState(submitForm, null);
return (
);
}
export default ContactForm;
解説ïŒ
'use client';ïŒ ãã®ãã£ã¬ã¯ãã£ãã¯ããããã¯ã©ã€ã¢ã³ãã³ã³ããŒãã³ãã§ããããšãReactã«äŒããŸããexperimental_useFormStateã¯ã¯ã©ã€ã¢ã³ãã³ã³ããŒãã³ãå ã§ãµãŒããŒã¢ã¯ã·ã§ã³ãšå¯Ÿè©±ããããã«äœ¿çšã§ããããããããå¿ èŠã§ããuseFormState(submitForm, null)ïŒ ãã®ããã¯ã¯2ã€ã®åŒæ°ãåããŸãïŒå®è¡ããããµãŒããŒã¢ã¯ã·ã§ã³ïŒsubmitFormïŒãšåæç¶æ ïŒãã®å Žåã¯nullïŒã§ããçŸåšã®ãã©ãŒã ç¶æ ãšããµãŒããŒã¢ã¯ã·ã§ã³ãããªã¬ãŒãã颿°ã®é åãè¿ããŸããè¿ããã`formAction`ã¯ããã©ãŒã ã®`action`ããããã£ã«æž¡ãå¿ èŠããããŸããform action={formAction}ïŒ ããã«ããããµãŒããŒã¢ã¯ã·ã§ã³ããã©ãŒã ã®éä¿¡ã«ãã€ã³ããããŸãããã©ãŒã ãéä¿¡ããããšããµãŒããŒäžã§submitFormã¢ã¯ã·ã§ã³ãå®è¡ãããŸããstate?.errorïŒ ãµãŒããŒã¢ã¯ã·ã§ã³ããè¿ããããšã©ãŒã¡ãã»ãŒãžã衚瀺ããŸããstate?.successïŒ ãµãŒããŒã¢ã¯ã·ã§ã³ããè¿ãããæåã¡ãã»ãŒãžã衚瀺ããŸããstate?.pendingïŒ ãµãŒããŒã¢ã¯ã·ã§ã³ã®å®è¡äžã¯èªåçã«trueã«èšå®ãããéä¿¡ãã¿ã³ãç¡å¹ã«ããããšãã§ããŸãã
ã³ãŒãã®è©³çްãªè§£èª¬
ã³ãŒããã¹ããããã€ã¹ãããã§åè§£ããŠãã©ã®ããã«æ©èœããããçè§£ããŸãããã
ãµãŒããŒã¢ã¯ã·ã§ã³ (server-actions.js)
'use server';ïŒ ãã®ãã£ã¬ã¯ãã£ãã¯ããã¡ã€ã«ã«ãµãŒããŒã¢ã¯ã·ã§ã³ãå«ãŸããŠããããšã瀺ããŸããReactããã®ãã¡ã€ã«å ã®é¢æ°ããµãŒããŒã§å®è¡ãããã¹ãã ãšçè§£ããããã«äžå¯æ¬ ã§ããasync function submitForm(prevState, formData)ïŒ ããã¯ãµãŒããŒã¢ã¯ã·ã§ã³é¢æ°ãå®çŸ©ããŸãã2ã€ã®åŒæ°ãåããŸãïŒprevStateïŒãã©ãŒã ã®åã®ç¶æ ïŒãšformDataïŒãã©ãŒã ããŒã¿ãå«ãFormDataã®ã€ã³ã¹ã¿ã³ã¹ïŒã§ããformData.get('name')ãformData.get('email')ãformData.get('message')ïŒ ãããã®è¡ã¯ãFormDataãªããžã§ã¯ããããã©ãŒã ããŒã¿ãæœåºããŸããget()ã®åŒæ°ã¯ããã©ãŒã å ã®å¯Ÿå¿ããå ¥åãã£ãŒã«ãã®name屿§ã§ãã- ãµãŒããŒãµã€ãããªããŒã·ã§ã³ïŒ ãã®ã³ãŒãã¯ãå¿ èŠãªãã¹ãŠã®ãã£ãŒã«ããååšããããšã確èªããããã®åºæ¬çãªãµãŒããŒãµã€ãããªããŒã·ã§ã³ãå®è¡ããŸããããããã®ãã£ãŒã«ããæ¬ ããŠããå Žåãã¯ã©ã€ã¢ã³ãã«ãšã©ãŒãªããžã§ã¯ããè¿ããŸãã
- ã¡ãŒã«éä¿¡ã®ã·ãã¥ã¬ãŒã·ã§ã³ïŒ ãã®ã³ãŒãã¯ã
await new Promise(resolve => setTimeout(resolve, 1000))ã䜿çšããŠã¡ãŒã«éä¿¡ãã·ãã¥ã¬ãŒãããŸããããã«ããããããã¯ãŒã¯ã®é å»¶ãã·ãã¥ã¬ãŒãããããã«1ç§ã®é å»¶ãå°å ¥ãããŸããå®éã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ããããå®éã®ã¡ãŒã«éä¿¡ããžãã¯ïŒäŸïŒNodemailerãSendGridã䜿çšïŒã«çœ®ãæããŸãã - ãšã©ãŒãã³ããªã³ã°ïŒ ãã®ã³ãŒãã«ã¯ãã¡ãŒã«éä¿¡ããã»ã¹äžã«çºçããå¯èœæ§ã®ãããšã©ãŒãåŠçããããã®
try...catchãããã¯ãå«ãŸããŠããŸãããšã©ãŒãçºçããå Žåãã³ã³ãœãŒã«ã«ãšã©ãŒãèšé²ããã¯ã©ã€ã¢ã³ãã«ãšã©ãŒãªããžã§ã¯ããè¿ããŸãã - ç¶æ
ã®è¿åŽïŒ ãµãŒããŒã¢ã¯ã·ã§ã³ã¯ããšã©ãŒã¡ãã»ãŒãžãŸãã¯æåã¡ãã»ãŒãžãå«ããªããžã§ã¯ããè¿ããŸãããã®ãªããžã§ã¯ããã
useFormStateããã¯ãä»ããŠã¯ã©ã€ã¢ã³ãã³ã³ããŒãã³ãã«æž¡ãããæ°ããç¶æ ã«ãªããŸãã
ã¯ã©ã€ã¢ã³ãã³ã³ããŒãã³ã (ContactForm.jsx)
'use client';ïŒ ãã®ãã£ã¬ã¯ãã£ãã¯ããã®ã³ã³ããŒãã³ããã¯ã©ã€ã¢ã³ãã³ã³ããŒãã³ãã§ãããuseStateãuseEffectã®ãããªã¯ã©ã€ã¢ã³ããµã€ãã®ããã¯ã䜿çšã§ããããšã瀺ããŸããããã¯ã䜿çšããDOMãšå¯Ÿè©±ããããã«ã¯å¿ é ã§ããconst [state, formAction] = useFormState(submitForm, null);ïŒ ãã®è¡ã¯experimental_useFormStateããã¯ãåŒã³åºããŸããæåã®åŒæ°ãšããŠsubmitFormãµãŒããŒã¢ã¯ã·ã§ã³ãã2çªç®ã®åŒæ°ãšããŠåæç¶æ ïŒnullïŒãæž¡ããŸããããã¯ã¯çŸåšã®ãã©ãŒã ç¶æ ïŒstateïŒãšãµãŒããŒã¢ã¯ã·ã§ã³ãããªã¬ãŒãã颿°ïŒformActionïŒãå«ãé åãè¿ããŸãã<form action={formAction}>ïŒ ããã«ããããã©ãŒã ã®action屿§ãformAction颿°ã«èšå®ãããŸãããã©ãŒã ãéä¿¡ããããšããã®é¢æ°ãåŒã³åºãããsubmitFormãµãŒããŒã¢ã¯ã·ã§ã³ãããªã¬ãŒãããŸãã<input type="text" id="name" name="name" />ã<input type="email" id="email" name="email" />ã<textarea id="message" name="message"></textarea>ïŒ ãããã¯ãã©ãŒã ã®å ¥åãã£ãŒã«ãã§ãããããã®ãã£ãŒã«ãã®name屿§ã¯ããµãŒããŒã¢ã¯ã·ã§ã³ã§formData.get('name')ãformData.get('email')ãformData.get('message')ã䜿çšããŠããŒã¿ã«ã¢ã¯ã»ã¹ããæ¹æ³ã決å®ãããããéèŠã§ãã<button type="submit" disabled={state?.pending}>éä¿¡</button>ïŒ ããã¯ãã©ãŒã ã®éä¿¡ãã¿ã³ã§ããdisabled={state?.pending}屿§ã¯ããã©ãŒã ããµãŒããŒã«éä¿¡ãããŠããéãã¿ã³ãç¡å¹ã«ãããŠãŒã¶ãŒããã©ãŒã ãè€æ°åéä¿¡ããã®ãé²ããŸãã{state?.error && <p style={{ color: 'red' }}>{state.error}</p>}ïŒ ããã¯ããã©ãŒã ã®ç¶æ ã«ãšã©ãŒãããå Žåã«æ¡ä»¶ä»ãã§ãšã©ãŒã¡ãã»ãŒãžãã¬ã³ããªã³ã°ããŸãããšã©ãŒã¡ãã»ãŒãžã¯èµ€è²ã§è¡šç€ºãããŸãã{state?.success && <p style={{ color: 'green' }}>{state.message}</p>}ïŒ ããã¯ããã©ãŒã ãæ£åžžã«éä¿¡ãããå Žåã«æ¡ä»¶ä»ãã§æåã¡ãã»ãŒãžãã¬ã³ããªã³ã°ããŸããæåã¡ãã»ãŒãžã¯ç·è²ã§è¡šç€ºãããŸãã
é«åºŠãªäœ¿çšæ³ãšèæ ®äºé
äžèšã®äŸã¯experimental_useFormStateã®åºæ¬çãªäœ¿çšæ³ã瀺ããŠããŸãããããè€éãªã¢ããªã±ãŒã·ã§ã³ã§äœ¿çšããéã«ã¯ãä»ã«ãããã€ãã®åŽé¢ãèæ
®ããå¿
èŠããããŸãã
ãªããã£ãã¹ãã£ãã¯ã¢ããããŒã
ãªããã£ãã¹ãã£ãã¯ã¢ããããŒããå®è£ ããããšã§ãããå¿çæ§ã®é«ããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãæäŸã§ããŸãããªããã£ãã¹ãã£ãã¯ã¢ããããŒããšã¯ããŠãŒã¶ãŒããã©ãŒã ãéä¿¡ããçŽåŸã«UIãæŽæ°ãããµãŒããŒã¢ã¯ã·ã§ã³ãæåãããšä»®å®ãããã®ã§ãããµãŒããŒã¢ã¯ã·ã§ã³ã倱æããå Žåã¯ãæŽæ°ãå ã«æ»ããŠãšã©ãŒã¡ãã»ãŒãžã衚瀺ã§ããŸãã
// ãªããã£ãã¹ãã£ãã¯ã¢ããããŒãã®äŸ
async function submitForm(prevState, formData) {
// UIãæ¥œèгçã«æŽæ°ãã
// (ããã¯éåžžããªã¹ããããŒãã«ã®ç¶æ
ãæŽæ°ããããšã«ãªã)
const id = Date.now(); // äžæçãªID
return {
optimisticUpdate: {
id: id,
name: formData.get('name'),
email: formData.get('email'),
}
}
}
// ã¯ã©ã€ã¢ã³ãã³ã³ããŒãã³ãå
:
const [state, formAction] = useFormState(submitForm, null);
// ãªããã£ãã¹ãã£ãã¯ã¢ããããŒããã¬ã³ããªã³ã°ããç¶æ
const [items, setItems] = useState([]);
useEffect(()=>{
if (state && state.optimisticUpdate) {
setItems(prev => [...prev, state.optimisticUpdate]);
}
}, [state])
ãã®ç°¡ç¥åãããäŸã§ã¯ããµãŒããŒã¢ã¯ã·ã§ã³ã¯optimisticUpdateããããã£ãè¿ããŸããã¯ã©ã€ã¢ã³ãã³ã³ããŒãã³ãã§ã¯ããããæœåºããŠã¢ããªã±ãŒã·ã§ã³ã§ã¬ã³ããªã³ã°ãããé
åã«è¿œå ããŸããäŸãã°ãããã¯ããã°æçš¿ã®ã³ã¡ã³ããªã¹ãã«æ°ããã³ã¡ã³ãã远å ããããšã衚ããããããŸããã
ãšã©ãŒãã³ããªã³ã°
广çãªãšã©ãŒãã³ããªã³ã°ã¯ãåªãããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã«ãšã£ãŠäžå¯æ¬ ã§ããexperimental_useFormStateã¯ããã©ãŒã éä¿¡äžã«çºçãããšã©ãŒã®åŠçã容æã«ããŸãããŠãŒã¶ãŒã«ãšã©ãŒã¡ãã»ãŒãžã衚瀺ãããšã©ãŒã®ä¿®æ£æ¹æ³ã«é¢ããã¬ã€ãã³ã¹ãæäŸã§ããŸãã
ãšã©ãŒãã³ããªã³ã°ã®ãã¹ããã©ã¯ãã£ã¹ãããã€ã玹ä»ããŸãïŒ
- æç¢ºã§å ·äœçãªãšã©ãŒã¡ãã»ãŒãžãæäŸããïŒ ãšã©ãŒã¡ãã»ãŒãžã¯ãçºçãããšã©ãŒã«å¯ŸããŠæç¢ºãç°¡æœããã€å ·äœçã§ããã¹ãã§ããããšã©ãŒãçºçããŸãããã®ãããªäžè¬çãªãšã©ãŒã¡ãã»ãŒãžã¯é¿ããŠãã ããã
- é¢é£ããå ¥åãã£ãŒã«ãã®è¿ãã«ãšã©ãŒã¡ãã»ãŒãžã衚瀺ããïŒ ãšã©ãŒã®åå ãšãªã£ãå ¥åãã£ãŒã«ãã®è¿ãã«ãšã©ãŒã¡ãã»ãŒãžã衚瀺ããŸããããã«ããããŠãŒã¶ãŒã¯ã©ã®ãã£ãŒã«ããä¿®æ£ããå¿ èŠãããããçè§£ãããããªããŸãã
- èŠèŠçãªåå³ã䜿çšããŠãšã©ãŒã匷調衚瀺ããïŒ èµ€ãããã¹ããæ ç·ãªã©ã®èŠèŠçãªåå³ã䜿çšããŠããšã©ãŒã®ããå ¥åãã£ãŒã«ãã匷調衚瀺ããŸãã
- ãšã©ãŒä¿®æ£ã®ææ¡ãæäŸããïŒ å¯èœã§ããã°ããšã©ãŒãä¿®æ£ããããã®ææ¡ãæäŸããŸããäŸãã°ããŠãŒã¶ãŒãç¡å¹ãªã¡ãŒã«ã¢ãã¬ã¹ãå ¥åããå Žåãæ£ãã圢åŒãææ¡ããŸãã
ã¢ã¯ã»ã·ããªãã£ã«é¢ããèæ ®äºé
ãã©ãŒã ãæ§ç¯ããéã«ã¯ãé害ãæã€äººã ããã©ãŒã ãå©çšã§ããããã«ãã¢ã¯ã»ã·ããªãã£ãèæ ®ããããšãéèŠã§ãã以äžã«çæãã¹ãã¢ã¯ã»ã·ããªãã£ã®èæ ®äºé ãããã€ã瀺ããŸãïŒ
- ã»ãã³ãã£ãã¯HTMLã䜿çšããïŒ
<label>ã<input>ã<textarea>ãªã©ã®ã»ãã³ãã£ãã¯HTMLèŠçŽ ã䜿çšããŠãã©ãŒã ãæ§é åããŸããããã«ãããæ¯æŽæè¡ããã©ãŒã ã®æ§é ãçè§£ãããããªããŸãã - ãã¹ãŠã®å
¥åãã£ãŒã«ãã«ã©ãã«ãæäŸããïŒ
<label>èŠçŽ ã䜿çšããŠããã¹ãŠã®å ¥åãã£ãŒã«ãã«ã©ãã«ãæäŸããŸãã<label>èŠçŽ ã®for屿§ã¯ã察å¿ããå ¥åãã£ãŒã«ãã®id屿§ãšäžèŽãããå¿ èŠããããŸãã - ARIA屿§ã䜿çšããïŒ ARIA屿§ã䜿çšããŠããã©ãŒã èŠçŽ ã«é¢ããè¿œå æ
å ±ãæ¯æŽæè¡ã«æäŸããŸããäŸãã°ã
aria-required屿§ã䜿çšããŠãå ¥åãã£ãŒã«ããå¿ é ã§ããããšã瀺ãããšãã§ããŸãã - ååãªã³ã³ãã©ã¹ãã確ä¿ããïŒ ããã¹ããšèæ¯è²ã®éã«ååãªã³ã³ãã©ã¹ããããããšã確èªããŸããããã«ããã匱èŠã®äººããã©ãŒã ãèªã¿ããããªããŸãã
- æ¯æŽæè¡ã§ãã¹ãããïŒ ã¹ã¯ãªãŒã³ãªãŒããŒãªã©ã®æ¯æŽæè¡ã§ãã©ãŒã ããã¹ãããé害ãæã€äººã ãå©çšã§ããããšã確èªããŸãã
åœéåïŒi18nïŒãšå°ååïŒl10nïŒ
ã°ããŒãã«ãªãªãŒãã£ãšã³ã¹åãã®ã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããå ŽåãåœéåïŒi18nïŒãšå°ååïŒl10nïŒã¯éåžžã«éèŠã§ããããã«ã¯ãã¢ããªã±ãŒã·ã§ã³ãç°ãªãèšèªãæåãå°åã«é©å¿ãããããšãå«ãŸããŸãã
experimental_useFormStateã䜿çšããéã®i18nãšl10nã«é¢ããèæ
®äºé
ãããã€ã瀺ããŸãïŒ
- ãšã©ãŒã¡ãã»ãŒãžãå°ååããïŒ ãŠãŒã¶ãŒã«è¡šç€ºããããšã©ãŒã¡ãã»ãŒãžãå°ååããŸããããã«ããããšã©ãŒã¡ãã»ãŒãžããŠãŒã¶ãŒã®åªå èšèªã§è¡šç€ºãããããã«ãªããŸãã
- ç°ãªãæ¥ä»ãšæ°å€ã®åœ¢åŒããµããŒãããïŒ ãŠãŒã¶ãŒã®ãã±ãŒã«ã«åºã¥ããŠãç°ãªãæ¥ä»ãšæ°å€ã®åœ¢åŒããµããŒãããŸãã
- å³ããå·Šãžã®èšèªãåŠçããïŒ ã¢ããªã±ãŒã·ã§ã³ãå³ããå·Šãžã®èšèªïŒäŸïŒã¢ã©ãã¢èªãããã©ã€èªïŒããµããŒãããŠããå Žåããã©ãŒã ã®ã¬ã€ã¢ãŠãããããã®èšèªã§æ£ãã衚瀺ãããããšã確èªããŸãã
- 翻蚳ã©ã€ãã©ãªã䜿çšããïŒ i18nextãreact-intlãªã©ã®ç¿»èš³ã©ã€ãã©ãªã䜿çšããŠç¿»èš³ã管çããŸãã
äŸãã°ãèŸæžã䜿çšããŠãšã©ãŒã¡ãã»ãŒãžãä¿åãããŠãŒã¶ãŒã®ãã±ãŒã«ã«åºã¥ããŠãããåç §ããããšãã§ããŸãã
// i18nextã䜿çšããäŸ
import i18next from 'i18next';
i18next.init({
resources: {
en: {
translation: {
"name_required": "ååã¯å¿
é ã§ã",
"email_required": "ã¡ãŒã«ã¢ãã¬ã¹ã¯å¿
é ã§ã",
}
},
fr: {
translation: {
"name_required": "ååã¯å¿
é ã§ã",
"email_required": "ã¡ãŒã«ã¢ãã¬ã¹ã¯å¿
é ã§ã",
}
}
},
lng: 'en',
fallbackLng: 'en',
interpolation: {
escapeValue: false // reactã¯ãã§ã«xssããä¿è·ããŠããŸã
}
});
// ãµãŒããŒã¢ã¯ã·ã§ã³å
:
if (!name) {
return { error: i18next.t("name_required") };
}
ãã®äŸã§ã¯ãi18nextã䜿çšããŠç¿»èš³ã管çããŠããŸããi18next.t()颿°ã¯ããŠãŒã¶ãŒã®ãã±ãŒã«ã«åºã¥ããŠç¿»èš³ããããšã©ãŒã¡ãã»ãŒãžãæ€çŽ¢ããããã«äœ¿çšãããŸãã
ã°ããŒãã«ãªèæ ®äºé ãšãã¹ããã©ã¯ãã£ã¹
ã°ããŒãã«ãªãªãŒãã£ãšã³ã¹åãã«Webã¢ããªã±ãŒã·ã§ã³ãéçºããéã«ã¯ãã·ãŒã ã¬ã¹ã§å æ¬çãªãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã確ä¿ããããã«ãããã€ãã®éèŠãªèæ ®äºé ãèæ ®ã«å ¥ããå¿ èŠããããŸãããããã®èæ ®äºé ã¯ãã¢ã¯ã»ã·ããªãã£ãæåçæåæ§ãããã©ãŒãã³ã¹æé©åãªã©ãããŸããŸãªåéã«åã³ãŸãã
ã¿ã€ã ãŸãŒã³
æ¥ä»ãšæå»ãæ±ãéã«ã¯ãã¿ã€ã ãŸãŒã³ãæ£ããåŠçããããšãäžå¯æ¬ ã§ãããŠãŒã¶ãŒã¯ç°ãªãã¿ã€ã ãŸãŒã³ã«ããå¯èœæ§ããããããæ¥ä»ãšæå»ããŠãŒã¶ãŒã®ããŒã«ã«ã¿ã€ã ãŸãŒã³ã§è¡šç€ºãããããã«ããå¿ èŠããããŸãã
ã¿ã€ã ãŸãŒã³ãåŠçããããã®ãã¹ããã©ã¯ãã£ã¹ãããã€ã玹ä»ããŸãïŒ
- æ¥ä»ãšæå»ãUTCã§ä¿åããïŒ ããŒã¿ããŒã¹ã«ã¯æ¥ä»ãšæå»ãUTCïŒåå®äžçæïŒã§ä¿åããŸããããã«ããããã¹ãŠã®æ¥æãã¿ã€ã ãŸãŒã³éã§äžè²«æ§ãä¿ã¡ãŸãã
- ã¿ã€ã ãŸãŒã³ã©ã€ãã©ãªã䜿çšããïŒ Moment.jsãLuxonãªã©ã®ã¿ã€ã ãŸãŒã³ã©ã€ãã©ãªã䜿çšããŠãæ¥ä»ãšæå»ããŠãŒã¶ãŒã®ããŒã«ã«ã¿ã€ã ãŸãŒã³ã«å€æããŸãã
- ãŠãŒã¶ãŒã«ã¿ã€ã ãŸãŒã³ã®æå®ãèš±å¯ããïŒ ãŠãŒã¶ãŒããããã¡ã€ã«èšå®ã§èªåã®ã¿ã€ã ãŸãŒã³ãæå®ã§ããããã«ããŸããããã«ãããæ¥ä»ãšæå»ããŠãŒã¶ãŒã®åžæããã¿ã€ã ãŸãŒã³ã§è¡šç€ºã§ããŸãã
é貚
ã¢ããªã±ãŒã·ã§ã³ãéèååŒãæ±ãå Žåãç°ãªãé貚ããµããŒãããå¿ èŠããããŸãããŠãŒã¶ãŒã¯ç°ãªãé貚ãæã€ç°ãªãåœã«ããå¯èœæ§ããããŸãã
é貚ãåŠçããããã®ãã¹ããã©ã¯ãã£ã¹ãããã€ã玹ä»ããŸãïŒ
- äŸ¡æ Œãäžè²«ããé貚ã§ä¿åããïŒ ããŒã¿ããŒã¹ã«ã¯äŸ¡æ Œãäžè²«ããé貚ïŒäŸïŒUSDïŒã§ä¿åããŸãã
- é貚æç®ã©ã€ãã©ãªã䜿çšããïŒ é貚æç®ã©ã€ãã©ãªã䜿çšããŠãäŸ¡æ ŒããŠãŒã¶ãŒã®çŸå°éè²šã«æç®ããŸãã
- æ£ããé貚èšå·ã§äŸ¡æ Œã衚瀺ããïŒ ãŠãŒã¶ãŒã®ãã±ãŒã«ã«åºã¥ããŠãæ£ããé貚èšå·ã§äŸ¡æ Œã衚瀺ããŸãã
- ãŠãŒã¶ãŒãé貚ãéžæã§ãããªãã·ã§ã³ãæäŸããïŒ ãŠãŒã¶ãŒãåžæããé貚ãéžæã§ããããã«ããŸãã
æåçæåæ§
ã°ããŒãã«ãªãªãŒãã£ãšã³ã¹åãã«Webã¢ããªã±ãŒã·ã§ã³ãéçºããéã«ã¯ãæåçã«ææã§ããããšãéèŠã§ããããã¯ãç°ãªãæåçèŠç¯ã䟡å€èгãèªèããäžå¿«ãŸãã¯ç¡ç¥çµãšèŠãªãããå¯èœæ§ã®ããã³ã³ãã³ããé¿ããããšãæå³ããŸãã
æåçæåæ§ã®ããã®ãã³ããããã€ã玹ä»ããŸãïŒ
- ã€ãã£ãªã ãã¹ã©ã³ã°ã®äœ¿çšãé¿ããïŒ ä»ã®æåã®äººã ã«ã¯çè§£ãããªãå¯èœæ§ã®ããã€ãã£ãªã ãã¹ã©ã³ã°ã®äœ¿çšã¯é¿ããŠãã ããã
- ç»åãã·ã³ãã«ã«æ³šæããïŒ ã¢ããªã±ãŒã·ã§ã³ã§äœ¿çšããç»åãã·ã³ãã«ã«ã¯æ³šæããŠãã ãããäžéšã®ç»åãã·ã³ãã«ã¯ãæåã«ãã£ãŠç°ãªãæå³ãæã€å ŽåããããŸãã
- ç°ãªã宿ç信念ãå°éããïŒ ç°ãªã宿ç信念ãå°éãã宿å£äœã«ãšã£ãŠäžå¿«ãšèŠãªãããå¯èœæ§ã®ããã³ã³ãã³ãã¯é¿ããŠãã ããã
- ç°ãªãæåçèŠç¯ãèªèããïŒ ç°ãªãæåçèŠç¯ã䟡å€èгãèªèããŠãã ãããäŸãã°ãäžéšã®æåã§ã¯ãçŽæ¥çãªã¢ã€ã³ã³ã¿ã¯ãã¯å€±ç€ŒãšèŠãªãããŸãã
ã°ããŒãã«ãªãŒãã£ãšã³ã¹åãã®ããã©ãŒãã³ã¹æé©å
äžçäžã®ãŠãŒã¶ãŒã¯ãã€ã³ã¿ãŒãããæ¥ç¶é床ãããã€ã¹ã®èœåãç°ãªããŸããå Žæãããã€ã¹ã«é¢ä¿ãªãããã¹ãŠã®ãŠãŒã¶ãŒã«ã¹ã ãŒãºã§å¿çæ§ã®é«ãäœéšãä¿èšŒããããã«ã¯ãã¢ããªã±ãŒã·ã§ã³ã®ããã©ãŒãã³ã¹ãæé©åããããšãäžå¯æ¬ ã§ãã
- ã³ã³ãã³ãããªããªãŒãããã¯ãŒã¯ïŒCDNïŒïŒ CDNã䜿çšããŠãã¢ããªã±ãŒã·ã§ã³ã®ã¢ã»ããïŒäŸïŒç»åãJavaScriptãCSSïŒãäžçäžã®ãµãŒããŒã«é ä¿¡ããŸããããã«ããããªãªãžã³ãµãŒããŒããé ãé¢ãããŠãŒã¶ãŒã®ã¬ã€ãã³ã·ãåæžãããŸãã
- ç»åæé©åïŒ ç»åãå§çž®ããé©åãªãã¡ã€ã«åœ¢åŒïŒäŸïŒWebPïŒã䜿çšããããšã§æé©åããŸããããã«ãããç»åã®ãã¡ã€ã«ãµã€ãºãåæžãããããŒãžã®èªã¿èŸŒã¿æéãççž®ãããŸãã
- ã³ãŒãåå²ïŒ ã³ãŒãåå²ã䜿çšããŠãã¢ããªã±ãŒã·ã§ã³ãããå°ããªãã£ã³ã¯ã«åå²ãããªã³ããã³ãã§èªã¿èŸŒããããã«ããŸããããã«ãããã¢ããªã±ãŒã·ã§ã³ã®åæèªã¿èŸŒã¿æéãççž®ãããŸãã
- ãã£ãã·ã³ã°ïŒ ãã£ãã·ã³ã°ã䜿çšããŠãé »ç¹ã«ã¢ã¯ã»ã¹ãããããŒã¿ããã©ãŠã¶ãŸãã¯ãµãŒããŒã«ä¿åããŸããããã«ãããã¢ããªã±ãŒã·ã§ã³ããµãŒããŒã«å¯ŸããŠè¡ããªã¯ãšã¹ãã®æ°ãåæžãããŸãã
- æå°åãšãã³ãã«ïŒ JavaScriptãšCSSãã¡ã€ã«ãæå°åãããã³ãã«ããŠãã¡ã€ã«ãµã€ãºãåæžããŸãã
experimental_useFormStateã®ä»£æ¿æ¡
experimental_useFormStateã¯ãµãŒããŒã¢ã¯ã·ã§ã³ãšã®çµã¿åããã§é
åçãªãã©ãŒã 管çã¢ãããŒããæäŸããŸããããŸã å®é𿮵éã«ããããšãèãããšã代æ¿ãœãªã¥ãŒã·ã§ã³ãèªèããŠããããšãéèŠã§ãã以äžã«ããã€ãã®äººæ°ã®ããä»£æ¿æ¡ã玹ä»ããŸãïŒ
- React Hook FormïŒ React Hook Formã¯ãéå¶åŸ¡ã³ã³ããŒãã³ãã䜿çšããããã©ãŒãã³ã¹ãé«ãæè»ãªãã©ãŒã ã©ã€ãã©ãªã§ããæå°éã®åã¬ã³ããªã³ã°ãšåªããããã©ãŒãã³ã¹ã§ç¥ãããŠããŸããYupãZodã®ãããªããªããŒã·ã§ã³ã©ã€ãã©ãªãšã®çµ±åãè¯å¥œã§ãã
- FormikïŒ Formikã¯ããã©ãŒã ã®ç¶æ 管çãããªããŒã·ã§ã³ãéä¿¡ãç°¡çŽ åãã人æ°ã®ãã©ãŒã ã©ã€ãã©ãªã§ããReact Hook Formãããé«ã¬ãã«ãªAPIãæäŸããè€éãªãã©ãŒã ã«é©ããŠããŸãã
- Redux FormïŒ Redux Formã¯ãReduxãšçµ±åãããã©ãŒã ã©ã€ãã©ãªã§ãããã§ã«ç¶æ 管çã«Reduxã䜿çšããŠããã¢ããªã±ãŒã·ã§ã³ã«é©ããŠããŸãã
- useStateãšuseRefã®äœ¿çšïŒ åçŽãªãã©ãŒã ã®å ŽåãReactã®
useStateããã¯ã䜿çšããŠçŽæ¥ãã©ãŒã ã®ç¶æ ã管çããuseRefã䜿çšããŠãã©ãŒã ã®å€ã«ã¢ã¯ã»ã¹ããããšãã§ããŸãããã®ã¢ãããŒãã¯ããæåã§ã®åŠçãå¿ èŠã§ããããã现ããªå¶åŸ¡ãå¿ èŠãªåºæ¬çãªãã©ãŒã ã«ã¯é©ããŠããå ŽåããããŸãã
çµè«
experimental_useFormStateã¯ãç¹ã«ãµãŒããŒã¢ã¯ã·ã§ã³ãšçµã¿åãããããšã§ãReactã®ãã©ãŒã 管çã«ããã倧ããªåé²ã衚ããŠããŸãããã©ãŒã ã®ç¶æ
ãåŠçãããµãŒããŒãµã€ãã®ããžãã¯ãšå¯Ÿè©±ãããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãåäžãããããã®ãããç°¡çŽ ã§å¹ççãªæ¹æ³ãæäŸããŸãããŸã å®é𿮵éã§ãããæ°ãããããžã§ã¯ãã§æ¢æ±ãã䟡å€ããããæçããã«ã€ããŠæ¢åã®ãããžã§ã¯ãã«ãæ€èšãã䟡å€ããããŸããããã¯ã广çãã€è²¬ä»»ãæã£ãŠäœ¿çšããããã«ã¯ãææ°ã®Reactããã¥ã¡ã³ããšãã¹ããã©ã¯ãã£ã¹ãåžžã«ç¢ºèªããããšãå¿ããªãã§ãã ããã
ãã®ã¬ã€ãã§æŠèª¬ãããååãçè§£ããç¹å®ã®ããŒãºã«åãããŠé©å¿ãããããšã§ãäžçäžã®ãŠãŒã¶ãŒã«åªãããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãæäŸãããå ç¢ã§ã¢ã¯ã»ã·ãã«ã§ã°ããŒãã«ã«å¯Ÿå¿ããWebã¢ããªã±ãŒã·ã§ã³ãäœæã§ããŸãããããã®ãã¹ããã©ã¯ãã£ã¹ãåãå ¥ããããšã¯ãã¢ããªã±ãŒã·ã§ã³ã®äœ¿ãããããåäžãããã ãã§ãªããå æ¬æ§ãšæåçæåæ§ãžã®ã³ãããã¡ã³ãã瀺ããæçµçã«ã¯ã°ããŒãã«èŠæš¡ã§ã®ãããžã§ã¯ãã®æåãšãªãŒãã«è²¢ç®ããŸãã
Reactãé²åãç¶ããäžã§ãexperimental_useFormStateã®ãããªããŒã«ã¯ãã¢ãã³ãªãµãŒããŒã¬ã³ããªã³ã°Reactã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããäžã§ãŸããŸãéèŠãªåœ¹å²ãæããã§ãããããããã®ããŒã«ãçè§£ãæŽ»çšããããšã¯ãæä»£ã®å
ãè¡ããåè¶ãããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãæäŸããããã«äžå¯æ¬ ã§ãã