ReactãµãŒããŒã¢ã¯ã·ã§ã³ã®ã¬ã¹ãã³ã¹ã¹ããªãŒãã³ã°ã§ããã°ã¬ãã·ããªãã©ãŒã å¿çãå®çŸãé«éã§å¿çæ§ã®é«ããã©ãŒã ãæ§ç¯ããUXãåäžãããæ¹æ³ã解説ããŸãã
ReactãµãŒããŒã¢ã¯ã·ã§ã³ã®ã¬ã¹ãã³ã¹ã¹ããªãŒãã³ã°ïŒUXåäžã®ããã®ããã°ã¬ãã·ããªãã©ãŒã å¿ç
ReactãµãŒããŒã¢ã¯ã·ã§ã³ã¯ãReactã¢ããªã±ãŒã·ã§ã³å ã§ãµãŒããŒãµã€ãã®æäœãåŠçããæ¹æ³ã«åŒ·åãªãã©ãã€ã ã·ããããããããŸããæããšããµã€ãã£ã³ã°ãªæ©èœã®äžã€ã¯ãã¬ã¹ãã³ã¹ãããã°ã¬ãã·ãã«ã¹ããªãŒãã³ã°ããèœåã§ãããããã«ããæäœå šäœãå®äºããåã§ããŠãŒã¶ãŒã«å³åº§ã®ãã£ãŒãããã¯ãæäŸã§ããŸããããã¯ç¹ã«ãã©ãŒã ã«ãšã£ãŠæçã§ãããããŒã¿ãå©çšå¯èœã«ãªãã«ã€ããŠUIãæŽæ°ããããšã§ãããå¿çæ§ãé«ãé åçãªãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãåµåºã§ããŸãã
ReactãµãŒããŒã¢ã¯ã·ã§ã³ãçè§£ãã
ãµãŒããŒã¢ã¯ã·ã§ã³ã¯ãReactã³ã³ããŒãã³ãããéå§ããããµãŒããŒäžã§å®è¡ãããéåæé¢æ°ã§ãããããã¯åŸæ¥ã®APIåŒã³åºãã«æ¯ã¹ãŠããã€ãã®å©ç¹ãæäŸããŸãïŒ
- ã»ãã¥ãªãã£ã®åäžïŒ ãµãŒããŒã¢ã¯ã·ã§ã³ã¯ãµãŒããŒäžã§çŽæ¥å®è¡ããããããæ©å¯ããŒã¿ãããžãã¯ãã¯ã©ã€ã¢ã³ãã«å ¬éããããªã¹ã¯ãäœæžããŸãã
- ãã€ã©ãŒãã¬ãŒãã®åæžïŒ ã¯ã©ã€ã¢ã³ãåŽã§åå¥ã®APIã«ãŒããããŒã¿ãã§ããã³ã°ããžãã¯ãäžèŠã«ãªããŸãã
- ããã©ãŒãã³ã¹ã®åŒ·åïŒ ãµãŒããŒãµã€ãã¬ã³ããªã³ã°ïŒSSRïŒãšãã£ãã·ã³ã°ã掻çšããŠãåæèªã¿èŸŒã¿æéãççž®ããããã©ãŒãã³ã¹ãåäžãããããšãã§ããŸãã
- åå®å šæ§ïŒ TypeScriptã䜿çšãããšããµãŒããŒã¢ã¯ã·ã§ã³ã¯ãšã³ãããŒãšã³ãã®åå®å šæ§ãæäŸããã¯ã©ã€ã¢ã³ããšãµãŒããŒéã®ããŒã¿ã®äžè²«æ§ãä¿èšŒããŸãã
ã¬ã¹ãã³ã¹ã¹ããªãŒãã³ã°ã®å
åŸæ¥ã®ãã©ãŒã éä¿¡ã§ã¯ããã¹ãŠã®ããŒã¿ããµãŒããŒã«éä¿¡ããå¿çãåŸ ã£ãŠããUIãæŽæ°ããããšããããããŸããããã¯ãç¹ã«è€éãªãã©ãŒã ãäœéãªãããã¯ãŒã¯æ¥ç¶ã®å Žåãäœæçãªé å»¶ã«ã€ãªããå¯èœæ§ããããŸããã¬ã¹ãã³ã¹ã¹ããªãŒãã³ã°ã«ããããµãŒããŒã¯ããŒã¿ããã£ã³ã¯ã§ã¯ã©ã€ã¢ã³ãã«éãè¿ãããšãã§ããããŒã¿ãå©çšå¯èœã«ãªãã«ã€ããŠUIãããã°ã¬ãã·ãã«æŽæ°ããããšãå¯èœã«ãªããŸãã
ãŠãŒã¶ãŒã®å ¥åã«åºã¥ããŠè€éãªäŸ¡æ Œãèšç®ãããã©ãŒã ãæ³åããŠã¿ãŠãã ãããèšç®å šäœãå®äºããã®ãåŸ ã€ä»£ããã«ããµãŒããŒã¯äžéçµæãã¯ã©ã€ã¢ã³ãã«ã¹ããªãŒãã³ã°ã§è¿ãããŠãŒã¶ãŒã«ãªã¢ã«ã¿ã€ã ã®ãã£ãŒãããã¯ãæäŸã§ããŸããããã«ããããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãå€§å¹ ã«åäžããã¢ããªã±ãŒã·ã§ã³ãããå¿çæ§ãé«ããšæããããããã«ãªããŸãã
ãµãŒããŒã¢ã¯ã·ã§ã³ã«ããããã°ã¬ãã·ããªãã©ãŒã å¿çã®å®è£
ReactãµãŒããŒã¢ã¯ã·ã§ã³ã䜿çšããŠããã°ã¬ãã·ããªãã©ãŒã å¿çãå®è£ ããæ¹æ³ã®äŸãèŠãŠãããŸãããã
äŸïŒãªã¢ã«ã¿ã€ã é貚ã³ã³ããŒã¿ãŒ
ãŠãŒã¶ãŒãéé¡ãå ¥åãããšãªã¢ã«ã¿ã€ã ã§çºæ¿ã¬ãŒãã®æŽæ°ãæäŸãããã·ã³ãã«ãªé貚ã³ã³ããŒã¿ãŒãã©ãŒã ãäœæããŸãã
1. ãµãŒããŒã¢ã¯ã·ã§ã³ã®èšå®
ãŸããé貚æç®ãåŠçãããµãŒããŒã¢ã¯ã·ã§ã³ãå®çŸ©ããŸãã
// server/actions.ts
'use server';
import { unstable_cache } from 'next/cache';
async function getExchangeRate(fromCurrency: string, toCurrency: string): Promise<number> {
// å€éšAPIããçºæ¿ã¬ãŒããååŸããã·ãã¥ã¬ãŒã·ã§ã³
console.log(`Fetching exchange rate for ${fromCurrency} to ${toCurrency}`);
await new Promise(resolve => setTimeout(resolve, 500)); // ãããã¯ãŒã¯é
å»¶ã®ã·ãã¥ã¬ãŒã·ã§ã³
if (fromCurrency === 'USD' && toCurrency === 'EUR') return 0.92;
if (fromCurrency === 'EUR' && toCurrency === 'USD') return 1.09;
if (fromCurrency === 'USD' && toCurrency === 'JPY') return 145;
if (fromCurrency === 'JPY' && toCurrency === 'USD') return 0.0069;
throw new Error(`Exchange rate not found for ${fromCurrency} to ${toCurrency}`);
}
export const convertCurrency = async (prevState: any, formData: FormData) => {
const fromCurrency = formData.get('fromCurrency') as string;
const toCurrency = formData.get('toCurrency') as string;
const amount = Number(formData.get('amount'));
try {
if (!fromCurrency || !toCurrency || isNaN(amount)) {
return { message: 'Please provide valid input.' };
}
// ã¬ã¹ãã³ã¹ã®ã¹ããªãŒãã³ã°ãã·ãã¥ã¬ãŒã·ã§ã³
await new Promise(resolve => setTimeout(resolve, 250));
const exchangeRate = await unstable_cache(
async () => getExchangeRate(fromCurrency, toCurrency),
[`exchange-rate-${fromCurrency}-${toCurrency}`],
{ tags: [`exchange-rate-${fromCurrency}-${toCurrency}`] }
)();
await new Promise(resolve => setTimeout(resolve, 250));
const convertedAmount = amount * exchangeRate;
return { message: `Converted amount: ${convertedAmount.toFixed(2)} ${toCurrency}` };
} catch (e: any) {
console.error(e);
return { message: 'Failed to convert currency.' };
}
};
ãã®äŸã§ã¯ãconvertCurrency
ãµãŒããŒã¢ã¯ã·ã§ã³ãçºæ¿ã¬ãŒããååŸãïŒé
å»¶ãã·ãã¥ã¬ãŒãïŒãæç®åŸã®éé¡ãèšç®ããŸããsetTimeout
ã䜿çšããŠäººçºçãªé
å»¶ã远å ãããããã¯ãŒã¯ã®ã¬ã€ãã³ã·ãã·ãã¥ã¬ãŒãããŠã¹ããªãŒãã³ã°å¹æã瀺ããŠããŸãã
2. Reactã³ã³ããŒãã³ãã®å®è£
次ã«ããµãŒããŒã¢ã¯ã·ã§ã³ã䜿çšããReactã³ã³ããŒãã³ããäœæããŸãã
// app/page.tsx
'use client';
import { useState, useTransition } from 'react';
import { convertCurrency } from './server/actions';
import { useFormState } from 'react-dom';
export default function CurrencyConverter() {
const [fromCurrency, setFromCurrency] = useState('USD');
const [toCurrency, setToCurrency] = useState('EUR');
const [amount, setAmount] = useState('');
const [isPending, startTransition] = useTransition();
const [state, formAction] = useFormState(convertCurrency, { message: '' });
const handleSubmit = async (event: React.FormEvent) => {
event.preventDefault();
startTransition(() => {
formAction(new FormData(event.target as HTMLFormElement));
});
};
return (
<div>
<h2>Real-Time Currency Converter</h2>
<form action={handleSubmit}>
<label htmlFor="fromCurrency">From:</label>
<select id="fromCurrency" name="fromCurrency" value={fromCurrency} onChange={(e) => setFromCurrency(e.target.value)}>
<option value="USD">USD</option>
<option value="EUR">EUR</option>
<option value="JPY">JPY</option>
</select>
<label htmlFor="toCurrency">To:</label>
<select id="toCurrency" name="toCurrency" value={toCurrency} onChange={(e) => setToCurrency(e.target.value)}>
<option value="EUR">EUR</option>
<option value="USD">USD</option>
<option value="JPY">JPY</option>
</select>
<label htmlFor="amount">Amount:</label>
<input
type="number"
id="amount"
name="amount"
value={amount}
onChange={(e) => setAmount(e.target.value)}
/>
<button type="submit" disabled={isPending}>
{isPending ? 'Converting...' : 'Convert'}
</button>
</form>
<p>{state.message}</p>
</div>
);
}
éèŠãªãã€ã³ãïŒ
useFormState
ããã¯ã䜿çšããŠãã©ãŒã ã®ç¶æ ã管çãããµãŒããŒã¢ã¯ã·ã§ã³ãåŒã³åºããŸããuseTransition
ããã®isPending
ç¶æ ã¯ãã¢ã¯ã·ã§ã³ã®å®è¡äžã«éä¿¡ãã¿ã³ãç¡å¹ã«ãããConverting...ãã¡ãã»ãŒãžã衚瀺ããŠãŠãŒã¶ãŒã«ãã£ãŒãããã¯ãäžããŸããuseFormState
ã«ãã£ãŠè¿ãããformAction
颿°ã¯ããã©ãŒã ã®éä¿¡ãèªåçã«åŠçãããµãŒããŒã¢ã¯ã·ã§ã³ããã®ã¬ã¹ãã³ã¹ã§ç¶æ ãæŽæ°ããŸãã
3. ããã°ã¬ãã·ããªæŽæ°ã®çè§£
ãŠãŒã¶ãŒããã©ãŒã ãéä¿¡ãããšãhandleSubmit
颿°ãåŒã³åºãããŸãããã©ãŒã ããFormData
ãªããžã§ã¯ããäœæãããããformAction
颿°ã«æž¡ããŸãããã®åŸããµãŒããŒã¢ã¯ã·ã§ã³ããµãŒããŒäžã§å®è¡ãããŸãããµãŒããŒã¢ã¯ã·ã§ã³ã«å°å
¥ããã人çºçãªé
å»¶ã®ããã以äžã®ãããªæåã芳å¯ãããŸãïŒ
- éä¿¡ãã¿ã³ãã»ãŒå³åº§ã«ãConverting...ãã«å€ãããŸãã
- çãé å»¶ïŒ250msïŒã®åŸãã³ãŒãã¯çºæ¿ã¬ãŒãã®ååŸãã·ãã¥ã¬ãŒãããŸãã
- æç®åŸã®éé¡ãèšç®ãããçµæãã¯ã©ã€ã¢ã³ãã«éãè¿ãããŸãã
- Reactã³ã³ããŒãã³ãã®
state.message
ãæŽæ°ãããæç®åŸã®éé¡ã衚瀺ãããŸãã
ããã¯ãã¬ã¹ãã³ã¹ã¹ããªãŒãã³ã°ã«ãã£ãŠãããŒã¿ãå©çšå¯èœã«ãªãã«ã€ããŠãŠãŒã¶ãŒã«äžéçãªæŽæ°ãæäŸããããå¿çæ§ãé«ãé åçãªãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã«ã€ãªããããšã瀺ããŠããŸãã
ããã°ã¬ãã·ããªãã©ãŒã å¿çã®å©ç¹
- ãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã®åäžïŒ ãŠãŒã¶ãŒã«å³åº§ã®ãã£ãŒãããã¯ãæäŸããã¢ããªã±ãŒã·ã§ã³ã®å¿çæ§ãé«ããé ããæããããŸããã
- äœæçãªã¬ã€ãã³ã·ã®åæžïŒ äžéçµæã衚瀺ããããšã§ãå šäœã®æäœã«åãæéãããã£ãŠãããŠãŒã¶ãŒã¯ããã»ã¹ãããéãæããŸãã
- ãšã³ã²ãŒãžã¡ã³ãã®åŒ·åïŒ ãªã¢ã«ã¿ã€ã ã®æŽæ°ãæäŸããããšã§ãŠãŒã¶ãŒã®é¢å¿ãåŒãã€ããäœæçãªé å»¶ã«ãããã©ãŒã ã®æŸæ£ãé²ããŸãã
- ã³ã³ããŒãžã§ã³çã®åäžïŒ ããã¹ã ãŒãºã§å¿çæ§ã®é«ããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã¯ãç¹ã«è€éãªãã©ãŒã ã«ãããŠãããé«ãã³ã³ããŒãžã§ã³çã«ã€ãªããå¯èœæ§ããããŸãã
é«åºŠãªãã¯ããã¯
1. `useOptimistic`ã«ãã峿UIæŽæ°
useOptimistic
ããã¯ã䜿çšãããšããµãŒããŒã¢ã¯ã·ã§ã³ãå®äºããåã«UIãæ¥œèгçã«æŽæ°ã§ããŸããããã«ãããUIãæåŸ
ãããçµæãå³åº§ã«åæ ãããããããã«é«éãªäœæå¿çæéãæäŸã§ããŸãã
import { useOptimistic } from 'react';
function MyComponent() {
const [optimisticState, addOptimistic] = useOptimistic(
initialState,
(state, newUpdate) => {
// æŽæ°ã«åºã¥ããŠæ°ããç¶æ
ãè¿ã
return { ...state, ...newUpdate };
}
);
const handleClick = async () => {
addOptimistic({ someValue: 'optimistic update' });
await myServerAction();
};
return (
<div>
<p>{optimisticState.someValue}</p>
<button onClick={handleClick}>Update</button>
</div>
);
}
é貚ã³ã³ããŒã¿ãŒã®äŸã§ã¯ãçŸåšã®çºæ¿ã¬ãŒãã«åºã¥ããŠæç®é¡ã楜芳çã«æŽæ°ãããµãŒããŒã§ã®å®éã®èšç®ãå®äºããåã«ãŠãŒã¶ãŒã«å³æã®ãã¬ãã¥ãŒãæäŸã§ããŸãããµãŒããŒããšã©ãŒãè¿ããå Žåãæ¥œèŠ³çæŽæ°ãå ã«æ»ãããšãã§ããŸãã
2. ãšã©ãŒãã³ããªã³ã°ãšãã©ãŒã«ããã¯ã¡ã«ããºã ã®å®è£
ãµãŒããŒã¢ã¯ã·ã§ã³ã倱æããå Žåããããã¯ãŒã¯æ¥ç¶ãäžæãããå Žåã«å¯ŸåŠããããã«ãå
ç¢ãªãšã©ãŒãã³ããªã³ã°ãšãã©ãŒã«ããã¯ã¡ã«ããºã ãå®è£
ããããšãéèŠã§ãããµãŒããŒã¢ã¯ã·ã§ã³å
ã§try...catch
ãããã¯ã䜿çšããŠãšã©ãŒãææããã¯ã©ã€ã¢ã³ãã«é©åãªãšã©ãŒã¡ãã»ãŒãžãè¿ãããšãã§ããŸãã
// server/actions.ts
export const convertCurrency = async (prevState: any, formData: FormData) => {
// ...
try {
// ...
} catch (error: any) {
console.error(error);
return { message: 'An error occurred while converting the currency. Please try again later.' };
}
};
ã¯ã©ã€ã¢ã³ãåŽã§ã¯ããŠãŒã¶ãŒã«ãšã©ãŒã¡ãã»ãŒãžã衚瀺ããæäœã®å詊è¡ããµããŒããžã®é£çµ¡ãªã©ã®ãªãã·ã§ã³ãæäŸã§ããŸãã
3. ããã©ãŒãã³ã¹åäžã®ããã®çºæ¿ã¬ãŒãã®ãã£ãã·ã³ã°
å€éšAPIããçºæ¿ã¬ãŒããååŸããããšã¯ãããã©ãŒãã³ã¹ã®ããã«ããã¯ã«ãªãå¯èœæ§ããããŸããããã©ãŒãã³ã¹ãåäžãããããã«ãRedisãMemcachedã®ãããªãã£ãã·ã³ã°ã¡ã«ããºã ã䜿çšããŠçºæ¿ã¬ãŒãããã£ãã·ã¥ããããšãã§ããŸããNext.jsã®unstable_cache
ïŒäŸã§äœ¿çšïŒã¯ãçµã¿èŸŒã¿ã®ãã£ãã·ã³ã°ãœãªã¥ãŒã·ã§ã³ãæäŸããŸããçºæ¿ã¬ãŒããææ°ã§ããããšãä¿èšŒããããã«ã宿çã«ãã£ãã·ã¥ãç¡å¹ã«ããããšãå¿ããªãã§ãã ããã
4. åœéåã«é¢ããèæ ®äºé
ã°ããŒãã«ãªãŠãŒã¶ãŒåãã®ã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããå ŽåãåœéåïŒi18nïŒãèæ ®ããããšãéèŠã§ããããã«ã¯ä»¥äžãå«ãŸããŸãïŒ
- æ°å€ã®æžåŒèšå®ïŒ ç°ãªããã±ãŒã«ã«åãããŠé©åãªæ°å€åœ¢åŒã䜿çšããŸãïŒäŸïŒå°æ°ç¹åºåãæåãšããŠã«ã³ããããªãªãã䜿çšïŒã
- éè²šã®æžåŒèšå®ïŒ ãŠãŒã¶ãŒã®ãã±ãŒã«ã«å¿ããŠé貚èšå·ãšåœ¢åŒã衚瀺ããŸãã
- æ¥ä»ãšæå»ã®æžåŒèšå®ïŒ ç°ãªããã±ãŒã«ã«åãããŠé©åãªæ¥ä»ãšæå»ã®åœ¢åŒã䜿çšããŸãã
- ããŒã«ã©ã€ãŒãŒã·ã§ã³ïŒ UIãç°ãªãèšèªã«ç¿»èš³ããŸãã
Intl
ãreact-intl
ã®ãããªã©ã€ãã©ãªã¯ãReactã¢ããªã±ãŒã·ã§ã³ã§i18nãå®è£
ããã®ã«åœ¹ç«ã¡ãŸãã
å®äžçã®äŸãšãŠãŒã¹ã±ãŒã¹
- Eã³ããŒã¹ïŒ ãŠãŒã¶ãŒãã«ãŒãã«ååã远å ããã«ã€ããŠããªã¢ã«ã¿ã€ã ã®éæãšé éäºå®æ¥ã衚瀺ããŸãã
- éèã¢ããªã±ãŒã·ã§ã³ïŒ ãªã¢ã«ã¿ã€ã ã®æ ªäŸ¡ãšããŒããã©ãªãªã®æŽæ°ãæäŸããŸãã
- æ è¡äºçŽïŒ ãªã¢ã«ã¿ã€ã ã®ãã©ã€ãäŸ¡æ Œãšç©ºåžç¶æ³ã衚瀺ããŸãã
- ããŒã¿å¯èŠåïŒ ãã£ãŒããã°ã©ããžã®ããŒã¿æŽæ°ãã¹ããªãŒãã³ã°ããŸãã
- ã³ã©ãã¬ãŒã·ã§ã³ããŒã«ïŒ ããã¥ã¡ã³ãããããžã§ã¯ããžã®ãªã¢ã«ã¿ã€ã ã®æŽæ°ã衚瀺ããŸãã
çµè«
ReactãµãŒããŒã¢ã¯ã·ã§ã³ã®ã¬ã¹ãã³ã¹ã¹ããªãŒãã³ã°ã¯ãReactã¢ããªã±ãŒã·ã§ã³ã®ãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãåäžããã匷åãªæ¹æ³ãæäŸããŸããããã°ã¬ãã·ããªãã©ãŒã å¿çãæäŸããããšã§ãããéããããå¿çæ§ãé«ããããé åçãªãã©ãŒã ãäœæãããŠãŒã¶ãŒã®é¢å¿ãç¶æããã³ã³ããŒãžã§ã³çãåäžãããããšãã§ããŸããã¬ã¹ãã³ã¹ã¹ããªãŒãã³ã°ãæ¥œèŠ³çæŽæ°ããã£ãã·ã³ã°ãªã©ã®ãã¯ããã¯ãšçµã¿åãããããšã§ãæ¬åœã«åè¶ãããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãæ§ç¯ã§ããŸãã
ReactãµãŒããŒã¢ã¯ã·ã§ã³ãé²åãç¶ããã«ã€ããŠãããã«åŒ·åãªæ©èœãèœåãç»å Žããè€éã§åçãªWebã¢ããªã±ãŒã·ã§ã³ã®éçºãããã«ç°¡çŽ åããããšãæåŸ ãããŸãã
ãããªãæ¢æ±
ãã®ã¬ã€ãã¯ãReactãµãŒããŒã¢ã¯ã·ã§ã³ã®ã¬ã¹ãã³ã¹ã¹ããªãŒãã³ã°ãšãããã°ã¬ãã·ããªãã©ãŒã å¿çãžã®ãã®å¿çšã«é¢ããå æ¬çãªæŠèŠãæäŸããŸããããã§èª¬æããæŠå¿µãšãã¯ããã¯ãçè§£ããããšã§ããã®åŒ·åãªæ©èœã掻çšããŠãããéããããå¿çæ§ãé«ããããé åçãªWebã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã§ããŸãã