ã«ã¹ã¿ã ããã¯éçºããã¹ã¿ãŒããåå©çšå¯èœãªããžãã¯ãã¯ãªãŒã³ãªã³ãŒããã¹ã±ãŒã©ãã«ãªã°ããŒãã«ã¢ããªã±ãŒã·ã§ã³ãå®çŸãReactããã¯ã®ç䟡ãæå€§éã«åŒãåºããŸãããã
Reactããã¯ãã¿ãŒã³ïŒã°ããŒãã«ã¢ããªã±ãŒã·ã§ã³ã®ããã®ã«ã¹ã¿ã ããã¯éçºãã¹ã¿ãŒã¬ã€ã
é²åãç¶ããWebéçºã®äžçã«ãããŠãReactã¯åçã§ã€ã³ã¿ã©ã¯ãã£ããªãŠãŒã¶ãŒã€ã³ã¿ãŒãã§ãŒã¹ãæ§ç¯ããããã®åºç€ãšããŠãäžè²«ããŠãã®å°äœãä¿ã£ãŠããŸãããReactããã¯ã®å°å ¥ã«ãããéçºè ã¯é¢æ°ã³ã³ããŒãã³ãã§ç¶æ ãšå¯äœçšã管çãã驿°çãªæ¹æ³ãæã«ããå€ãã®ã·ããªãªã§ã¯ã©ã¹ã³ã³ããŒãã³ãã®å¿ èŠæ§ã广çã«çœ®ãæããŸããããã®ãã©ãã€ã ã·ããã¯ãããã¯ãªãŒã³ã§ãããç°¡æœã§ãåå©çšæ§ã®é«ãã³ãŒãããããããŸããã
ããã¯ã®æã匷åãªæ©èœã®äžã€ããã«ã¹ã¿ã ããã¯ãäœæããèœåã§ããã«ã¹ã¿ã ããã¯ã¯ãååããuseãã§å§ãŸããä»ã®ããã¯ãåŒã³åºãããšãã§ããJavaScript颿°ã§ããããã«ãããã³ã³ããŒãã³ãã®ããžãã¯ãåå©çšå¯èœãªé¢æ°ã«æœåºã§ããããè¯ãçµç¹åããã¹ãå®¹ææ§ãã¹ã±ãŒã©ããªãã£ãä¿é²ããŸãããããã¯ã倿§ãªã°ããŒãã«ãªãŒãã£ãšã³ã¹ã«ãµãŒãã¹ãæäŸããã¢ããªã±ãŒã·ã§ã³ã«ãšã£ãŠæ¥µããŠéèŠãªåŽé¢ã§ãã
ãã®å æ¬çãªã¬ã€ãã§ã¯ãã«ã¹ã¿ã ããã¯ã®éçºã«çŠç¹ãåœãŠãReactããã¯ã®ãã¿ãŒã³ãæ·±ãæãäžããŸãããªãã«ã¹ã¿ã ããã¯ãäžå¯æ¬ ãªã®ãã广çã«æ§ç¯ããæ¹æ³ãäžè¬çãªãã¿ãŒã³ãé«åºŠãªãã¯ããã¯ããããŠäžçäžã®ãŠãŒã¶ãŒã®ããã«èšèšãããå ç¢ã§é«æ§èœãªã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããã®éèŠãªèæ ®äºé ã«ã€ããŠæ¢ããŸãã
Reactããã¯ã®åºç€ãçè§£ãã
ã«ã¹ã¿ã ããã¯ã«é£ã³èŸŒãåã«ãçµã¿èŸŒã¿ã®Reactããã¯ã®åºç€ãææ¡ããããšãäžå¯æ¬ ã§ãããããã¯ã颿°ã³ã³ããŒãã³ãã«ãããç¶æ 管çãšå¯äœçšã«å¿ èŠãªããªããã£ããæäŸããŸãã
ããã¯ã®åºæ¬åå
useState: ããŒã«ã«ã³ã³ããŒãã³ãã®ç¶æ ã管çããŸããã¹ããŒããã«ãªå€ãšãããæŽæ°ããããã®é¢æ°ãè¿ããŸããuseEffect: ããŒã¿ãã§ããã賌èªãDOMã®æå倿Žãªã©ã颿°ã³ã³ããŒãã³ãã§å¯äœçšãå®è¡ããŸããæ¯åã®ã¬ã³ããªã³ã°åŸã«å®è¡ãããŸããããã®åäœã¯äŸåé åã§å¶åŸ¡ã§ããŸããuseContext: React Contextããå€ãæ¶è²»ããããããã¹ã®ãã±ããªã¬ãŒãªãã§ã³ã³ããŒãã³ãããªãŒãéããŠããŒã¿ãæž¡ãããšãã§ããŸããuseRef:.currentããããã£ãæž¡ãããåŒæ°ã§åæåãããã倿Žå¯èœãªrefãªããžã§ã¯ããè¿ããŸããDOMèŠçŽ ãžã®ã¢ã¯ã»ã¹ããåã¬ã³ããªã³ã°ãåŒãèµ·ãããã«ã¬ã³ããªã³ã°éã§å€ãæ°žç¶åãããã®ã«äŸ¿å©ã§ããuseCallback: äŸåé¢ä¿ã®ããããã倿Žãããå Žåã«ã®ã¿å€åãããã³ãŒã«ããã¯é¢æ°ã®ã¡ã¢åãããããŒãžã§ã³ãè¿ããŸããäžèŠãªåã¬ã³ããªã³ã°ãé²ãããã«åç §ã®ç䟡æ§ã«äŸåããåã³ã³ããŒãã³ãã®æé©åã«åœ¹ç«ã¡ãŸããuseMemo: äŸåé¢ä¿ã®ããããã倿Žãããå Žåã«ã®ã¿åèšç®ããããã¡ã¢åãããå€ãè¿ããŸããã³ã¹ãã®é«ãèšç®ã«åœ¹ç«ã¡ãŸããuseReducer:useStateã®ä»£æ¿ã§ãããè€éãªç¶æ ããžãã¯ã«å¯Ÿå¿ããŸããReduxã«äŒŒãŠãããç¶æ é·ç§»ãè€æ°ã®ãµãå€ãå«ãå Žåããæ¬¡ã®ç¶æ ãåã®ç¶æ ã«äŸåããå Žåã«äœ¿çšãããŸãã
ããã¯ã®ã«ãŒã«ïŒ å¿ããŠã¯ãªããªãã®ã¯ãããã¯ã«ã¯2ã€ã®éèŠãªã«ãŒã«ãããããããã¯ã«ã¹ã¿ã ããã¯ã«ãé©çšããããšããããšã§ãïŒ
- ãããã¬ãã«ã§ã®ã¿ããã¯ãåŒã³åºãïŒ ã«ãŒããæ¡ä»¶åå²ããã¹ãããã颿°ã®å éšã§ããã¯ãåŒã³åºããªãã§ãã ããã
- Reactã®é¢æ°ããã®ã¿ããã¯ãåŒã³åºãïŒ Reactã®é¢æ°ã³ã³ããŒãã³ããŸãã¯ä»ã®ã«ã¹ã¿ã ããã¯ããåŒã³åºããŠãã ããã
ã«ã¹ã¿ã ããã¯ã®åïŒãªãéçºããã®ãïŒ
ã«ã¹ã¿ã ããã¯ã¯åãªãä»»æã®æ©èœã§ã¯ãããŸãããçŸä»£ã®Reactéçºã«ãããéèŠãªèª²é¡ã«å¯ŸåŠããç¹ã«äžè²«æ§ãšä¿å®æ§ã«é¢ããã°ããŒãã«ãªèŠä»¶ãæã€ãããžã§ã¯ããå«ããããããèŠæš¡ã®ãããžã§ã¯ãã«å®è³ªçãªã¡ãªããããããããŸãã
åå©çšå¯èœãªããžãã¯ã®ã«ãã»ã«å
ã«ã¹ã¿ã ããã¯ã®èåŸã«ããäž»ãªåæ©ã¯ãã³ãŒãã®åå©çšã§ããããã¯ä»¥åã¯ãé«éã³ã³ããŒãã³ãïŒHOCïŒãã¬ã³ããŒããããã®ãããªãã¿ãŒã³ãããžãã¯ã®å ±æã«äœ¿çšãããŠããŸãããããããã¯ãã°ãã°ã©ãããŒå°çãè€éãªããããåœåãã³ã³ããŒãã³ãããªãŒã®éå±€ã®æ·±åã«ã€ãªãããŸãããã«ã¹ã¿ã ããã¯ã䜿çšãããšãããªãŒã«æ°ããã³ã³ããŒãã³ããå°å ¥ããããšãªããã¹ããŒããã«ãªããžãã¯ãæœåºããŠåå©çšã§ããŸãã
ããŒã¿ã®ãã§ããããã©ãŒã å ¥åã®ç®¡çããã©ãŠã¶ã€ãã³ãã®åŠçãªã©ã®ããžãã¯ãèããŠã¿ãŠãã ããããã®ã³ãŒããè€æ°ã®ã³ã³ããŒãã³ãã§è€è£œãã代ããã«ãã«ã¹ã¿ã ããã¯ã«ã«ãã»ã«åããå¿ èŠãªå Žæã§ã€ã³ããŒãããŠäœ¿çšããã ãã§ããããã«ãããå®åçãªã³ãŒããåæžãããã¢ããªã±ãŒã·ã§ã³å šäœã§äžè²«æ§ã確ä¿ãããŸããããã¯ãäžçäžã®ç°ãªãããŒã ãéçºè ãåãã³ãŒãããŒã¹ã«è²¢ç®ããå Žåã«äžå¯æ¬ ã§ãã
é¢å¿ã®åé¢
ã«ã¹ã¿ã ããã¯ã¯ããã¬ãŒã³ããŒã·ã§ã³ããžãã¯ïŒUIãã©ã®ããã«èŠãããïŒãšããžãã¹ããžãã¯ïŒããŒã¿ãã©ã®ããã«åŠçããããïŒã®ããã¯ãªãŒã³ãªåé¢ãä¿é²ããŸããã³ã³ããŒãã³ãã¯ã¬ã³ããªã³ã°ã«å°å¿µã§ããã«ã¹ã¿ã ããã¯ã¯ããŒã¿ãã§ãããããªããŒã·ã§ã³ã賌èªããã®ä»ã®éããžã¥ã¢ã«ãªããžãã¯ã®è€éããåŠçã§ããŸããããã«ãããã³ã³ããŒãã³ãã¯ããå°ãããèªã¿ããããçè§£ããããã°ãä¿®æ£ã容æã«ãªããŸãã
ãã¹ãå®¹ææ§ã®åäž
ã«ã¹ã¿ã ããã¯ã¯ç¹å®ã®ããžãã¯ãã«ãã»ã«åãããããåäœãã¹ããåç¬ã§å®¹æã«ãªããŸããReactã³ã³ããŒãã³ãå
šäœãã¬ã³ããªã³ã°ãããããŠãŒã¶ãŒã®ã€ã³ã¿ã©ã¯ã·ã§ã³ãã·ãã¥ã¬ãŒããããããããšãªããããã¯ã®åäœããã¹ãã§ããŸãã@testing-library/react-hooksã®ãããªã©ã€ãã©ãªã¯ãã«ã¹ã¿ã ããã¯ãç¬ç«ããŠãã¹ãããããã®ãŠãŒãã£ãªãã£ãæäŸããæ¥ç¶ãããŠããUIã«é¢ä¿ãªãã³ã¢ããžãã¯ãæ£ããæ©èœããããšãä¿èšŒããŸãã
å¯èªæ§ãšä¿å®æ§ã®åäž
è€éãªããžãã¯ãèšè¿°çãªååãæã€ã«ã¹ã¿ã ããã¯ã«æœè±¡åããããšã§ãã³ã³ããŒãã³ãã¯ã¯ããã«èªã¿ããããªããŸããuseAuth()ãuseShoppingCart()ããŸãã¯useGeolocation()ã䜿çšããŠããã³ã³ããŒãã³ãã¯ãå®è£
ã®è©³çްã«é£ã³èŸŒãããšãªãããã®æ©èœãå³åº§ã«äŒããŸãããã®æç¢ºãã¯ãç¹ã«ç°ãªãèšèªçãŸãã¯æè²çèæ¯ãæã€éçºè
ãå
±æãããžã§ã¯ãã§ååããå Žåã«ãå€§èŠæš¡ãªããŒã ã«ãšã£ãŠéåžžã«äŸ¡å€ããããŸãã
ã«ã¹ã¿ã ããã¯ã®æ§é
ã«ã¹ã¿ã ããã¯ã®äœæã¯ããã®åºæ¬çãªæ§é ãšèŠçŽãçè§£ããã°ç°¡åã§ãã
åœåèŠåïŒãuseããã¬ãã£ãã¯ã¹
æ
£äŸã«ããããã¹ãŠã®ã«ã¹ã¿ã ããã¯ã¯ãuseããšããåèªã§å§ããªããã°ãªããŸããïŒäŸïŒuseCounter, useInput, useDebounceïŒããã®åœåèŠåã¯ãReactã®ãªã³ã¿ãŒïŒããã³ä»ã®éçºè
ïŒã«å¯ŸããŠããã®é¢æ°ãããã¯ã®ã«ãŒã«ã«åŸããå
éšã§ä»ã®ããã¯ãåŒã³åºãå¯èœæ§ãããããšã瀺ããŸããããã¯Reactèªäœã«ãã£ãŠå³å¯ã«åŒ·å¶ãããããã§ã¯ãããŸããããããŒã«ã®äºææ§ãšã³ãŒãã®æç¢ºæ§ã®ããã«éèŠãªèŠçŽã§ãã
ã«ã¹ã¿ã ããã¯ã«é©çšãããããã¯ã®ã«ãŒã«
çµã¿èŸŒã¿ã®ããã¯ãšåæ§ã«ãã«ã¹ã¿ã ããã¯ãããã¯ã®ã«ãŒã«ã«åŸããªããã°ãªããŸãããããã¯ãä»ã®ããã¯ïŒuseState, useEffectãªã©ïŒãã«ã¹ã¿ã ããã¯é¢æ°ã®ãããã¬ãã«ã§ã®ã¿åŒã³åºããããšãæå³ããŸããã«ã¹ã¿ã ããã¯å
ã®æ¡ä»¶æãã«ãŒãããã¹ãããã颿°ã®äžã§ããããåŒã³åºãããšã¯ã§ããŸããã
åŒæ°ã®åãæž¡ããšå€ã®è¿åŽ
ã«ã¹ã¿ã ããã¯ã¯éåžžã®JavaScript颿°ãªã®ã§ãåŒæ°ãåãåããä»»æã®å€ïŒç¶æ ã颿°ããªããžã§ã¯ããé åïŒãè¿ãããšãã§ããŸãããã®æè»æ§ã«ãããããã¯ãé«åºŠã«èšå®å¯èœã«ããæ¶è²»ããã³ã³ããŒãã³ããå¿ èŠãšãããã®ãæ£ç¢ºã«å ¬éã§ããŸãã
äŸïŒã·ã³ãã«ãªuseCounterããã¯
ã€ã³ã¯ãªã¡ã³ãããã³ãã¯ãªã¡ã³ãå¯èœãªæ°å€ç¶æ
ã管çãããåºæ¬çãªuseCounterããã¯ãäœæããŠã¿ãŸãããã
import React, { useState, useCallback } from 'react';
/**
* A custom hook to manage a numerical counter.
* @param {number} initialValue - The initial value of the counter. Defaults to 0.
* @returns {{ count: number, increment: () => void, decrement: () => void, reset: () => void }}
*/
function useCounter(initialValue = 0) {
const [count, setCount] = useState(initialValue);
const increment = useCallback(() => {
setCount(prevCount => prevCount + 1);
}, []); // No dependencies, as setCount is stable
const decrement = useCallback(() => {
setCount(prevCount => prevCount - 1);
}, []); // No dependencies
const reset = useCallback(() => {
setCount(initialValue);
}, [initialValue]); // Depends on initialValue
return {
count,
increment,
decrement,
reset
};
}
export default useCounter;
ãããŠãã³ã³ããŒãã³ãã§ã©ã®ããã«äœ¿çšãããã®äŸã§ãïŒ
import React from 'react';
import useCounter from './useCounter'; // Assuming useCounter.js is in the same directory
function CounterComponent() {
const { count, increment, decrement, reset } = useCounter(10);
return (
<div>
<h3>Current Count: {count}</h3>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={reset}>Reset</button>
</div>
);
}
export default CounterComponent;
ãã®ç°¡åãªäŸã¯ãã«ãã»ã«åãåå©çšæ§ããããŠæç¢ºãªé¢å¿ã®åé¢ã瀺ããŠããŸããCounterComponentã¯ã«ãŠã³ã¿ãŒã®ããžãã¯ãã©ã®ããã«æ©èœããããæ°ã«ãããåã«useCounterã«ãã£ãŠæäŸããã颿°ãšç¶æ
ã䜿çšããŸãã
äžè¬çãªReactããã¯ã®ãã¿ãŒã³ãšå®è·µçãªã«ã¹ã¿ã ããã¯ã®äŸ
ã«ã¹ã¿ã ããã¯ã¯éåžžã«æ±çšæ§ãé«ããå¹ åºãäžè¬çãªéçºã·ããªãªã«é©çšã§ããŸããããã€ãã®äžè¬çãªãã¿ãŒã³ãæ¢ã£ãŠã¿ãŸãããã
1. ããŒã¿ãã§ããããã¯ïŒuseFetch / useAPIïŒ
éåæã®ããŒã¿ãã§ãããããŒãã£ã³ã°ç¶æ ããšã©ãŒãã³ããªã³ã°ã®ç®¡çã¯ç¹°ãè¿ãçºçããã¿ã¹ã¯ã§ããã«ã¹ã¿ã ããã¯ã¯ãã®è€éããæœè±¡åããã³ã³ããŒãã³ããããŒã¿ããã§ããããã®ã§ã¯ãªãã¬ã³ããªã³ã°ããããšã«éäžãããããã¯ãªãŒã³ã«ããããšãã§ããŸãã
import React, { useState, useEffect, useCallback } from 'react';
/**
* A custom hook for fetching data from an API.
* @param {string} url - The URL to fetch data from.
* @param {object} options - Fetch options (e.g., headers, method, body).
* @returns {{ data: any, loading: boolean, error: Error | null, refetch: () => void }}
*/
function useFetch(url, options = {}) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const fetchData = useCallback(async () => {
setLoading(true);
setError(null);
try {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
setData(result);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
}, [url, JSON.stringify(options)]); // Stringify options for deep comparison
useEffect(() => {
fetchData();
}, [fetchData]);
return { data, loading, error, refetch: fetchData };
}
export default useFetch;
䜿çšäŸïŒ
import React from 'react';
import useFetch from './useFetch';
function UserProfile({ userId }) {
const { data: user, loading, error } = useFetch(`https://api.example.com/users/${userId}`);
if (loading) return <p>Loading user profile...</p>;
if (error) return <p style={{ color: 'red' }}>Error: {error.message}</p>;
if (!user) return <p>No user data found.</p>;
return (
<div>
<h2>{user.name}</h2>
<p>Email: {user.email}</p>
<p>Location: {user.location}</p>
<!-- More user details -->
</div>
);
}
export default UserProfile;
ã°ããŒãã«ã¢ããªã±ãŒã·ã§ã³ã§ã¯ãuseFetchããã¯ãããã«åŒ·åããŠããšã©ãŒã¡ãã»ãŒãžã®åœéåãå°åã«åºã¥ããç°ãªãAPIãšã³ããã€ã³ãã®åŠçããããã¯ã°ããŒãã«ãªãã£ãã·ã¥æŠç¥ãšã®çµ±åãªã©ãè¡ãããšãã§ããŸãã
2. ç¶æ
管çããã¯ïŒuseLocalStorage, useToggleïŒ
åçŽãªã³ã³ããŒãã³ãã®ç¶æ ãè¶ ããŠãã«ã¹ã¿ã ããã¯ã¯ããè€éãŸãã¯æ°žç¶çãªç¶æ ã®èŠä»¶ã管çã§ããŸãã
useLocalStorageïŒã»ãã·ã§ã³ããŸããã§ç¶æ
ãæ°žç¶å
ãã®ããã¯ã䜿çšãããšããã©ãŠã¶ã®localStorageããç¶æ
ã®äžéšãä¿åããã³ååŸã§ãããŠãŒã¶ãŒããã©ãŠã¶ãéããŠãæ°žç¶åãããããšãã§ããŸããããã¯ãããŒãèšå®ããŠãŒã¶ãŒèšå®ããŸãã¯è€æ°ã¹ãããã®ãã©ãŒã ã§ã®ãŠãŒã¶ãŒã®éžæãèšæ¶ããã®ã«æé©ã§ãã
import React, { useState, useEffect } from 'react';
/**
* A custom hook to persist state in localStorage.
* @param {string} key - The key for localStorage.
* @param {any} initialValue - The initial value if no data is found in localStorage.
* @returns {[any, (value: any) => void]}
*/
function useLocalStorage(key, initialValue) {
// State to store our value
// Pass initial state function to useState so logic is only executed once
const [storedValue, setStoredValue] = useState(() => {
try {
const item = typeof window !== 'undefined' ? window.localStorage.getItem(key) : null;
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.error(`Error reading localStorage key "${key}":`, error);
return initialValue;
}
});
// useEffect to update localStorage when the state changes
useEffect(() => {
try {
if (typeof window !== 'undefined') {
window.localStorage.setItem(key, JSON.stringify(storedValue));
}
} catch (error) {
console.error(`Error writing to localStorage key "${key}":`, error);
}
}, [key, storedValue]);
return [storedValue, setStoredValue];
}
export default useLocalStorage;
䜿çšäŸïŒããŒãåãæ¿ãïŒïŒ
import React from 'react';
import useLocalStorage from './useLocalStorage';
function ThemeSwitcher() {
const [isDarkMode, setIsDarkMode] = useLocalStorage('theme-preference', false);
const toggleTheme = () => {
setIsDarkMode(prevMode => !prevMode);
document.body.className = isDarkMode ? '' : 'dark-theme'; // Apply CSS class
};
return (
<div>
<p>Current Theme: {isDarkMode ? '<strong>Dark</strong>' : '<strong>Light</strong>'}</p>
<button onClick={toggleTheme}>
Switch to {isDarkMode ? 'Light' : 'Dark'} Theme
</button>
</div>
);
}
export default ThemeSwitcher;
useToggle / useBooleanïŒã·ã³ãã«ãªçåœå€ã®ç¶æ
管ç
ã¢ãŒãã«ãããããããŠã³ããã§ãã¯ããã¯ã¹ãªã©ã§é »ç¹ã«äœ¿çšããããçåœå€ã®ç¶æ ã管çããããã®ã³ã³ãã¯ããªããã¯ã§ãã
import { useState, useCallback } from 'react';
/**
* A custom hook to manage a boolean state.
* @param {boolean} initialValue - The initial boolean value. Defaults to false.
* @returns {[boolean, () => void, (value: boolean) => void]}
*/
function useToggle(initialValue = false) {
const [value, setValue] = useState(initialValue);
const toggle = useCallback(() => {
setValue(prev => !prev);
}, []);
return [value, toggle, setValue];
}
export default useToggle;
䜿çšäŸïŒ
import React from 'react';
import useToggle from './useToggle';
function ModalComponent() {
const [isOpen, toggleOpen] = useToggle(false);
return (
<div>
<button onClick={toggleOpen}>Toggle Modal</button>
{isOpen && (
<div style={{
border: '1px solid black',
padding: '20px',
margin: '10px',
backgroundColor: 'lightblue'
}}>
<h3>This is a Modal</h3>
<p>Content goes here.</p>
<button onClick={toggleOpen}>Close Modal</button>
</div>
)}
</div>
);
}
export default ModalComponent;
3. ã€ãã³ããªã¹ã㌠/ DOMæäœããã¯ïŒuseEventListener, useOutsideClickïŒ
ãã©ãŠã¶ã®DOMãã°ããŒãã«ã€ãã³ããšã®å¯Ÿè©±ã«ã¯ãã€ãã³ããªã¹ããŒã®è¿œå ãšåé€ã䌎ããé©åãªã¯ãªãŒã³ã¢ãããå¿ èŠã§ããã«ã¹ã¿ã ããã¯ã¯ããã®ãã¿ãŒã³ãã«ãã»ã«åããã®ã«åªããŠããŸãã
useEventListenerïŒç°¡ç¥åãããã€ãã³ããã³ããªã³ã°
ãã®ããã¯ã¯ãã€ãã³ããªã¹ããŒã®è¿œå ãšåé€ã®ããã»ã¹ãæœè±¡åããã³ã³ããŒãã³ããã¢ã³ããŠã³ãããããäŸåé¢ä¿ã倿Žããããšãã«ã¯ãªãŒã³ã¢ãããä¿èšŒããŸãã
import { useEffect, useRef } from 'react';
/**
* A custom hook to attach and clean up event listeners.
* @param {string} eventName - The name of the event (e.g., 'click', 'resize').
* @param {function} handler - The event handler function.
* @param {EventTarget} element - The DOM element to attach the listener to. Defaults to window.
* @param {object} options - Event listener options (e.g., { capture: true }).
*/
function useEventListener(eventName, handler, element = window, options = {}) {
// Create a ref that stores handler
const savedHandler = useRef();
// Update ref.current value if handler changes. This allows the effect below to
// always use the latest handler without needing to re-attach the event listener.
useEffect(() => {
savedHandler.current = handler;
}, [handler]);
useEffect(() => {
// Ensure the element supports addEventListener
const isSupported = element && element.addEventListener;
if (!isSupported) return;
// Create event listener that calls savedHandler.current
const eventListener = event => savedHandler.current(event);
// Add event listener
element.addEventListener(eventName, eventListener, options);
// Clean up on unmount or when dependencies change
return () => {
element.removeEventListener(eventName, eventListener, options);
};
}, [eventName, element, options]); // Re-run if eventName or element changes
}
export default useEventListener;
䜿çšäŸïŒããŒæŒäžã®æ€åºïŒïŒ
import React, { useState } from 'react';
import useEventListener from './useEventListener';
function KeyPressDetector() {
const [key, setKey] = useState('None');
const handleKeyPress = (event) => {
setKey(event.key);
};
useEventListener('keydown', handleKeyPress);
return (
<div>
<p>Press any key to see its name:</p>
<strong>Last Key Pressed: {key}</strong>
</div>
);
}
export default KeyPressDetector;
4. ãã©ãŒã ãã³ããªã³ã°ããã¯ïŒuseFormïŒ
ãã©ãŒã ã¯ã»ãšãã©ãã¹ãŠã®ã¢ããªã±ãŒã·ã§ã³ã®äžå¿ã§ããã«ã¹ã¿ã ããã¯ã¯ãå ¥åç¶æ ã®ç®¡çãããªããŒã·ã§ã³ãéä¿¡ããžãã¯ãå¹çåããè€éãªãã©ãŒã ã管çããããããŸãã
import { useState, useCallback } from 'react';
/**
* A custom hook for managing form state and handling input changes.
* @param {object} initialValues - An object with initial form field values.
* @param {object} validationRules - An object with validation functions for each field.
* @returns {{ values: object, errors: object, handleChange: (e: React.ChangeEvent) => void, handleSubmit: (callback: (values: object) => void) => (e: React.FormEvent) => void, resetForm: () => void }}
*/
function useForm(initialValues, validationRules = {}) {
const [values, setValues] = useState(initialValues);
const [errors, setErrors] = useState({});
const handleChange = useCallback((event) => {
event.persist(); // Persist the event to use it asynchronously (if needed)
const { name, value, type, checked } = event.target;
setValues((prevValues) => ({
...prevValues,
[name]: type === 'checkbox' ? checked : value,
}));
// Clear error for the field as soon as it's changed
if (errors[name]) {
setErrors((prevErrors) => {
const newErrors = { ...prevErrors };
delete newErrors[name];
return newErrors;
});
}
}, [errors]);
const validate = useCallback(() => {
const newErrors = {};
for (const fieldName in validationRules) {
if (validationRules.hasOwnProperty(fieldName)) {
const rule = validationRules[fieldName];
const value = values[fieldName];
if (rule && !rule(value)) {
newErrors[fieldName] = `Invalid ${fieldName}`;
// In a real app, you'd provide specific error messages based on the rule
}
}
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
}, [values, validationRules]);
const handleSubmit = useCallback((callback) => (event) => {
event.preventDefault();
const isValid = validate();
if (isValid) {
callback(values);
}
}, [values, validate]);
const resetForm = useCallback(() => {
setValues(initialValues);
setErrors({});
}, [initialValues]);
return {
values,
errors,
handleChange,
handleSubmit,
resetForm,
};
}
export default useForm;
䜿çšäŸïŒãã°ã€ã³ãã©ãŒã ïŒïŒ
import React from 'react';
import useForm from './useForm';
const emailRegex = /^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/;
function LoginForm() {
const { values, errors, handleChange, handleSubmit } = useForm(
{ email: '', password: '' },
{
email: (value) => emailRegex.test(value) && value.length > 0,
password: (value) => value.length >= 6,
}
);
const submitLogin = (formData) => {
alert(`Submitting: Email: ${formData.email}, Password: ${formData.password}`);
// In a real app, send data to an API
};
return (
<form onSubmit={handleSubmit(submitLogin)}>
<h2>Login</h2>
<div>
<label htmlFor="email">Email:</label>
<input
type="email"
id="email"
name="email"
value={values.email}
onChange={handleChange}
/>
{errors.email && <p style={{ color: 'red' }}>{errors.email}</p>}
</div>
<div>
<label htmlFor="password">Password:</label>
<input
type="password"
id="password"
name="password"
value={values.password}
onChange={handleChange}
/>
{errors.password && <p style={{ color: 'red' }}>{errors.password}</p>}
</div>
<button type="submit">Login</button>
</form>
);
}
export default LoginForm;
ã°ããŒãã«ã¢ããªã±ãŒã·ã§ã³ã§ã¯ããã®`useForm`ããã¯ãæ¡åŒµããŠãããªããŒã·ã§ã³ã¡ãã»ãŒãžã®i18nãå«ãããããã±ãŒã«ã«åºã¥ããŠç°ãªãæ¥ä»/æ°å€åœ¢åŒãåŠçããããåœåºæã®äœæããªããŒã·ã§ã³ãµãŒãã¹ãšçµ±åãããããããšãã§ããŸãã
ã«ã¹ã¿ã ããã¯ã®é«åºŠãªãã¯ããã¯ãšãã¹ããã©ã¯ãã£ã¹
ã«ã¹ã¿ã ããã¯ã®åæ
ã«ã¹ã¿ã ããã¯ã®æã匷åãªåŽé¢ã®1ã€ã¯ããã®åæå¯èœæ§ã§ããå°ããªåçŽãªã³ã³ããŒãã³ãããè€éãªã³ã³ããŒãã³ããæ§ç¯ããããã«ãããåçŽãªããã¯ãçµã¿åãããŠè€éãªããã¯ãæ§ç¯ã§ããŸããããã«ãããé«åºŠã«ã¢ãžã¥ãŒã«åãããä¿å®å¯èœãªããžãã¯ãå¯èœã«ãªããŸãã
äŸãã°ãæŽç·ŽãããuseChatããã¯ã¯ãå
éšã§useWebSocketïŒWebSocketæ¥ç¶çšã®ã«ã¹ã¿ã ããã¯ïŒãšuseScrollIntoViewïŒã¹ã¯ããŒã«åäœã管çããããã®ã«ã¹ã¿ã ããã¯ïŒã䜿çšãããããããŸããã
ã°ããŒãã«ãªç¶æ 管çã®ããã®Context APIãšã«ã¹ã¿ã ããã¯
ã«ã¹ã¿ã ããã¯ã¯ããŒã«ã«ã®ç¶æ ãšããžãã¯ã«åªããŠããŸãããReactã®Context APIãšçµã¿åãããŠã°ããŒãã«ãªç¶æ ã管çããããšãã§ããŸãããã®ãã¿ãŒã³ã¯ãç¹ã«ã°ããŒãã«ãªç¶æ ãé床ã«è€éã§ãªããããã«ãŠã§ã¢ãå¿ èŠãšããªãå€ãã®ã¢ããªã±ãŒã·ã§ã³ã§ãReduxã®ãããªãœãªã¥ãŒã·ã§ã³ã广çã«çœ®ãæããŸãã
// AuthContext.js
import React, { createContext, useContext, useState, useEffect, useCallback } from 'react';
const AuthContext = createContext(null);
// Custom Hook for Authentication Logic
export function useAuth() {
const [user, setUser] = useState(null);
const [isLoading, setIsLoading] = useState(true);
// Simulate an async login function
const login = useCallback(async (username, password) => {
setIsLoading(true);
return new Promise(resolve => {
setTimeout(() => {
if (username === 'test' && password === 'password') {
const userData = { id: '123', name: 'Global User' };
setUser(userData);
localStorage.setItem('user', JSON.stringify(userData));
resolve(true);
} else {
resolve(false);
}
setIsLoading(false);
}, 1000);
});
}, []);
// Simulate an async logout function
const logout = useCallback(() => {
setUser(null);
localStorage.removeItem('user');
}, []);
// Load user from localStorage on mount
useEffect(() => {
const storedUser = localStorage.getItem('user');
if (storedUser) {
try {
setUser(JSON.parse(storedUser));
} catch (e) {
console.error('Failed to parse user from localStorage', e);
localStorage.removeItem('user');
}
}
setIsLoading(false);
}, []);
return { user, isLoading, login, logout };
}
// AuthProvider component to wrap your application or parts of it
export function AuthProvider({ children }) {
const auth = useAuth(); // This is where our custom hook is used
return (
<AuthContext.Provider value={auth}>
{children}
</AuthContext.Provider>
);
}
// Custom Hook to consume the AuthContext
export function useAuthContext() {
const context = useContext(AuthContext);
if (context === undefined) {
throw new Error('useAuthContext must be used within an AuthProvider');
}
return context;
}
䜿çšäŸïŒ
// App.js (or root component)
import React from 'react';
import { AuthProvider, useAuthContext } from './AuthContext';
function Dashboard() {
const { user, isLoading, logout } = useAuthContext();
if (isLoading) return <p>Loading authentication status...</p>;
if (!user) return <p>Please log in.</p>;
return (
<div>
<h2>Welcome, {user.name}!</h2>
<button onClick={logout}>Logout</button>
</div>
);
}
function LoginFormForContext() {
const { login } = useAuthContext();
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const handleLogin = async (e) => {
e.preventDefault();
const success = await login(username, password);
if (!success) {
alert('Login failed!');
}
};
return (
<form onSubmit={handleLogin}>
<input type="text" placeholder="Username" value={username} onChange={e => setUsername(e.target.value)} />
<input type="password" placeholder="Password" value={password} onChange={e => setPassword(e.target.value)} />
<button type="submit">Login</button>
</form>
);
}
function App() {
return (
<AuthProvider>
<h1>Auth Example with Custom Hook & Context</h1>
<LoginFormForContext />
<Dashboard />
</AuthProvider>
);
}
export default App;
éåææäœã®äžå¯§ãªæ±ãæ¹
ã«ã¹ã¿ã ããã¯å
ã§éåææäœïŒããŒã¿ãã§ãããªã©ïŒãå®è¡ããå Žåãç«¶åç¶æ
ãã¢ã³ããŠã³ããããã³ã³ããŒãã³ãã®ç¶æ
ãæŽæ°ããããšãããªã©ã®æœåšçãªåé¡ãåŠçããããšãéèŠã§ããAbortControllerã䜿çšããããã³ã³ããŒãã³ãã®ããŠã³ãç¶æ
ã远跡ããããã®refã䜿çšããã®ãäžè¬çãªæŠç¥ã§ãã
// Example of AbortController in useFetch (simplified for clarity)
import React, { useState, useEffect } from 'react';
function useFetchAbortable(url) {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const abortController = new AbortController();
const signal = abortController.signal;
setLoading(true);
setError(null);
fetch(url, { signal })
.then(response => {
if (!response.ok) throw new Error(response.statusText);
return response.json();
})
.then(setData)
.catch(err => {
if (err.name === 'AbortError') {
console.log('Fetch aborted');
} else {
setError(err);
}
})
.finally(() => setLoading(false));
return () => {
// Abort fetch request if component unmounts or dependencies change
abortController.abort();
};
}, [url]);
return { data, error, loading };
}
export default useFetchAbortable;
ããã¯å
ã§ã®useCallbackãšuseMemoã«ããã¡ã¢å
ã«ã¹ã¿ã ããã¯èªäœãæ¬è³ªçã«ããã©ãŒãã³ã¹ã®åé¡ãåŒãèµ·ããããã§ã¯ãããŸããããããããè¿ãå€ã颿°ã¯åé¡ãåŒãèµ·ããå¯èœæ§ããããŸããã«ã¹ã¿ã ããã¯ãæ¯åã®ã¬ã³ããªã³ã°ã§åäœæããã颿°ããªããžã§ã¯ããè¿ããããããã¡ã¢åãããåã³ã³ããŒãã³ãïŒäŸïŒReact.memoã§ã©ãããããã³ã³ããŒãã³ãïŒã«ããããã¹ãšããŠæž¡ããããšãäžèŠãªåã¬ã³ããªã³ã°ã«ã€ãªããå¯èœæ§ããããŸããã³ã³ããŒãã³ãå
ã§è¡ãã®ãšåæ§ã«ãuseCallbackã颿°ã«ãuseMemoããªããžã§ã¯ã/é
åã«äœ¿çšããŠãã¬ã³ããªã³ã°éã§å®å®ããåç
§ã確ä¿ããŸãã
ã«ã¹ã¿ã ããã¯ã®ãã¹ã
ã«ã¹ã¿ã ããã¯ã®ä¿¡é Œæ§ã確ä¿ããããã«ã¯ããã¹ããäžå¯æ¬ ã§ãã@testing-library/react-hooksïŒçŸåšã¯@testing-library/reactã®äžéšãšããŠrenderHookïŒã®ãããªã©ã€ãã©ãªã¯ãããã¯ã®ããžãã¯ãåé¢ããããã³ã³ããŒãã³ãã«äŸåããªãæ¹æ³ã§ãã¹ãããããã®ãŠãŒãã£ãªãã£ãæäŸããŸããããã¯ã®å
¥åãšåºåãããã³ãã®å¯äœçšã®ãã¹ãã«éäžããŠãã ããã
// Example test for useCounter (conceptual)
import { renderHook, act } from '@testing-library/react-hooks';
import useCounter from './useCounter';
describe('useCounter', () => {
it('should increment the count', () => {
const { result } = renderHook(() => useCounter(0));
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});
it('should reset the count to initial value', () => {
const { result } = renderHook(() => useCounter(5));
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(6);
act(() => {
result.current.reset();
});
expect(result.current.count).toBe(5);
});
// More tests for decrement, initial value, etc.
});
ããã¥ã¡ã³ããŒã·ã§ã³ãšçºèŠå¯èœæ§
ã«ã¹ã¿ã ããã¯ãçã«åå©çšå¯èœã§ããããã«ã¯ãç¹ã«å€§èŠæš¡ãªããŒã ããªãŒãã³ãœãŒã¹ãããžã§ã¯ãã§ã¯ãååã«ææžåãããŠããå¿ èŠããããŸããããã¯ãäœãããã®ãããã®ãã©ã¡ãŒã¿ããããŠäœãè¿ãã®ããæç¢ºã«èª¬æããŸããæç¢ºãã®ããã«JSDocã³ã¡ã³ãã䜿çšããŠãã ãããå ±æããã¯ãnpmããã±ãŒãžãšããŠå ¬éããè€æ°ã®ãããžã§ã¯ãããã€ã¯ãããã³ããšã³ãéã§å®¹æã«çºèŠããã³ããŒãžã§ã³ç®¡çã§ããããã«ããããšãæ€èšããŠãã ããã
ã°ããŒãã«ãªèæ ®äºé ãšããã©ãŒãã³ã¹æé©å
ã°ããŒãã«ãªãªãŒãã£ãšã³ã¹åãã®ã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããéãã«ã¹ã¿ã ããã¯ã¯ã倿§ãªç°å¢ã«ãããåœéåãã¢ã¯ã»ã·ããªãã£ãããã©ãŒãã³ã¹ã«é¢é£ããè€éããæœè±¡åããäžã§éèŠãªåœ¹å²ãæããããšãã§ããŸãã
ããã¯ã«ãããåœéåïŒi18nïŒ
ã«ã¹ã¿ã ããã¯ã¯ãåœéåã«é¢é£ããããžãã¯ãã«ãã»ã«åã§ããŸããäŸãã°ãuseTranslationããã¯ïŒreact-i18nextã®ãããªi18nã©ã€ãã©ãªã«ãã£ãŠæäŸãããããšãå€ãïŒã¯ãã³ã³ããŒãã³ãã翻蚳ãããæååã«ã¢ã¯ã»ã¹ã§ããããã«ããŸããåæ§ã«ãuseLocaleDateãuseLocalizedCurrencyããã¯ãæ§ç¯ããŠããŠãŒã¶ãŒã®ãã±ãŒã«ã«å¿ããŠæ¥ä»ãæ°å€ãé貚ããã©ãŒãããããäžçäžã§äžè²«ãããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã確ä¿ããããšãã§ããŸãã
// Conceptual useLocalizedDate hook
import { useState, useEffect } from 'react';
function useLocalizedDate(dateString, locale = 'en-US', options = {}) {
const [formattedDate, setFormattedDate] = useState('');
useEffect(() => {
try {
const date = new Date(dateString);
setFormattedDate(date.toLocaleDateString(locale, options));
} catch (e) {
console.error('Invalid date string provided to useLocalizedDate:', dateString, e);
setFormattedDate('Invalid Date');
}
}, [dateString, locale, JSON.stringify(options)]);
return formattedDate;
}
// Usage:
// const myDate = useLocalizedDate('2023-10-26T10:00:00Z', 'de-DE', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
// // myDate would be 'Donnerstag, 26. Oktober 2023'
ã¢ã¯ã»ã·ããªãã£ïŒa11yïŒã®ãã¹ããã©ã¯ãã£ã¹
ã«ã¹ã¿ã ããã¯ã¯ãã¢ã¯ã»ã·ããªãã£ã®ãã¹ããã©ã¯ãã£ã¹ã匷å¶ããã®ã«åœ¹ç«ã¡ãŸããäŸãã°ãuseFocusTrapããã¯ã¯ããŒããŒãããã²ãŒã·ã§ã³ãã¢ãŒãã«ãã€ã¢ãã°å
ã«çãŸãããšãä¿èšŒããããuseAnnouncerããã¯ã¯åçãªã³ã³ãã³ãæŽæ°ã®ããã«ã¹ã¯ãªãŒã³ãªãŒããŒã«ã¡ãã»ãŒãžãéä¿¡ãããããŠãäžçäžã®é害ãæã€å人ã®ãŠãŒã¶ããªãã£ãåäžãããããšãã§ããŸãã
ããã©ãŒãã³ã¹ïŒãããŠã³ã¹ãšã¹ããããªã³ã°
æ€çŽ¢åè£ãæã€å ¥åãã£ãŒã«ããããŠãŒã¶ãŒå ¥åã«ãã£ãŠããªã¬ãŒãããéãèšç®ã§ã¯ããããŠã³ã¹ãã¹ããããªã³ã°ãããã©ãŒãã³ã¹ãå€§å¹ ã«åäžãããããšãã§ããŸãããããã®ãã¿ãŒã³ã¯ãã«ã¹ã¿ã ããã¯ã«æé©ã§ãã
useDebounceïŒå€ã®æŽæ°ãé
å»¶ããã
ãã®ããã¯ã¯ãå€ã®ãããŠã³ã¹ãããããŒãžã§ã³ãè¿ããŸããã€ãŸããæåŸã®å€æŽããäžå®ã®é å»¶ã®åŸã«ã®ã¿å€ãæŽæ°ãããŸããæ€çŽ¢ããŒãå ¥åããªããŒã·ã§ã³ããŸãã¯ãã¹ãŠã®ããŒã¹ãããŒã¯ã§çºç«ãã¹ãã§ãªãAPIåŒã³åºãã«äŸ¿å©ã§ãã
import { useState, useEffect } from 'react';
/**
* A custom hook to debounce a value.
* @param {any} value - The value to debounce.
* @param {number} delay - The delay in milliseconds.
* @returns {any} The debounced value.
*/
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
}
export default useDebounce;
䜿çšäŸïŒã©ã€ãæ€çŽ¢ïŒïŒ
import React, { useState } from 'react';
import useDebounce from './useDebounce';
function SearchInput() {
const [searchTerm, setSearchTerm] = useState('');
const debouncedSearchTerm = useDebounce(searchTerm, 500); // 500ms delay
// Effect for fetching search results based on debouncedSearchTerm
useEffect(() => {
if (debouncedSearchTerm) {
console.log(`Fetching results for: ${debouncedSearchTerm}`);
// Make API call here
} else {
console.log('Search term cleared.');
}
}, [debouncedSearchTerm]);
return (
<div>
<input
type="text"
placeholder="Search..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<p>Searching for: <strong>{debouncedSearchTerm || '...'}</strong></p>
</div>
);
}
export default SearchInput;
ãµãŒããŒãµã€ãã¬ã³ããªã³ã°ïŒSSRïŒãšã®äºææ§
SSRã¢ããªã±ãŒã·ã§ã³ïŒäŸïŒNext.js, RemixïŒçšã®ã«ã¹ã¿ã ããã¯ãéçºããå ŽåãuseEffectãšuseLayoutEffectã¯ã¯ã©ã€ã¢ã³ãåŽã§ã®ã¿å®è¡ãããããšãèŠããŠãããŠãã ãããããã¯ã«ãµãŒããŒã¬ã³ããªã³ã°ãã§ãŒãºäžã«å®è¡ããå¿
èŠãããããžãã¯ïŒäŸïŒããŒãžããã€ãã¬ãŒãããåæããŒã¿ãã§ããïŒãå«ãŸããŠããå Žåã代æ¿ãã¿ãŒã³ã䜿çšãããããã®ãããªããžãã¯ããµãŒããŒäžã§é©åã«åŠçãããããã«ããå¿
èŠããããŸãããã©ãŠã¶ã®DOMãwindowãªããžã§ã¯ããšçŽæ¥å¯Ÿè©±ããããã¯ã¯ãéåžžããµãŒããŒå®è¡ãé²ãããã®ã¬ãŒãïŒäŸïŒtypeof window !== 'undefined'ïŒãèšããã¹ãã§ãã
çµè«ïŒReactéçºã¯ãŒã¯ãããŒãã°ããŒãã«ã«åŒ·åãã
Reactã®ã«ã¹ã¿ã ããã¯ã¯åãªã䟿å©ãªæ©èœä»¥äžã®ãã®ã§ãããReactã¢ããªã±ãŒã·ã§ã³ã§ããžãã¯ãæ§é åãåå©çšããæ¹æ³ã«ãããæ ¹æ¬çãªå€åã衚ããŠããŸããã«ã¹ã¿ã ããã¯éçºããã¹ã¿ãŒããããšã§ã以äžã®èœåãåŸãããšãã§ããŸãïŒ
- ããDRYãªã³ãŒããæžãïŒ å ±éã®ããžãã¯ãäžå åããããšã§éè€ãæé€ããŸãã
- å¯èªæ§ã®åäžïŒ ã³ã³ããŒãã³ããç°¡æœã«ããäž»èŠãªUIã®è²¬ä»»ã«éäžãããŸãã
- ãã¹ãå®¹ææ§ã®åäžïŒ è€éãªããžãã¯ãåé¢ãã容æã«ãã¹ãããŸãã
- ä¿å®æ§ã®åäžïŒ å°æ¥ã®æŽæ°ããã°ä¿®æ£ãç°¡çŽ åããŸãã
- ã³ã©ãã¬ãŒã·ã§ã³ã®ä¿é²ïŒ ã°ããŒãã«ããŒã å ã§å ±ææ©èœã®ããã®æç¢ºã§ååã«å®çŸ©ãããAPIãæäŸããŸãã
- ããã©ãŒãã³ã¹ã®æé©åïŒ ãããŠã³ã¹ãã¡ã¢åã®ãããªãã¿ãŒã³ã广çã«å®è£ ããŸãã
ã°ããŒãã«ãªãªãŒãã£ãšã³ã¹ã«å¯Ÿå¿ããã¢ããªã±ãŒã·ã§ã³ã«ãšã£ãŠãã«ã¹ã¿ã ããã¯ã®æ§é åããã¢ãžã¥ãŒã«åãããæ§è³ªã¯ç¹ã«æçã§ããããã«ãããéçºè ã¯å€æ§ãªèšèªçãæåçãæè¡çèŠä»¶ã«å¯Ÿå¿ã§ããå ç¢ã§äžè²«æ§ã®ãããé©å¿å¯èœãªãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãæ§ç¯ã§ããŸããå°èŠæš¡ãªå éšããŒã«ãæ§ç¯ããŠããå Žåã§ããå€§èŠæš¡ãªãšã³ã¿ãŒãã©ã€ãºã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããŠããå Žåã§ããã«ã¹ã¿ã ããã¯ã®ãã¿ãŒã³ãåãå ¥ããããšã¯ãééããªãããå¹ççã§ã楜ãããã¹ã±ãŒã©ãã«ãªReactéçºäœéšã«ã€ãªããã§ãããã
仿¥ããèªåèªèº«ã®ã«ã¹ã¿ã ããã¯ã詊ãå§ããŠãã ãããã³ã³ããŒãã³ãå ã®ç¹°ãè¿ãçŸããããžãã¯ãç¹å®ãããããæœåºããããªãã®ã³ãŒãããŒã¹ãããã¯ãªãŒã³ã§ããã匷åã§ãã°ããŒãã«ã«å¯Ÿå¿ããReactã¢ããªã±ãŒã·ã§ã³ã«å€ãã£ãŠããã®ãèŠãŠãã ããã