when there is a circumstance of code duplication of two components doing the similar task
(Ex1) ForwardCounter and BackwardCounter
src/hooks/use-counter.js
import { useState, useEffect } from 'react';
// can get a parameter
// can also set a default value of a parameter
const useCounter = (forwards) => {
const [counter, setCounter] = useState(0);
useEffect(()=> {
const interval = setInterval(() => {
if (forwards) {
setCounter((prevCounter) => prevCounter + 1);
} else {
setCounter((prevCounter) => prevCounter - 1);
}
}, 1000);
return () => clearInterval(interval);
}, [forwards]);
// since a parameter is a new dependency,
// we should add it a dependenct in useEffect
return counter;
};
export default useCounter;
using custom hooks
ForwardCounter.js
import useCounter from ~
const ForwardCounter = () => {
const counter = useCounter(true);
return <Card>{counter}</Card>
}
BackwardCounter.js
import useCounter from ~
const BackwardCounter = () => {
const counter = useCounter(false);
return <Card>{counter}</Card>
}
(Ex2) Requesting GET and POST request
code it flexibily considering the dependencies of useEffect and useCallback (since putting all the states/functions used in a function as dependencies can trigger an infinite loop)
hooks/use-https.js
const useHttp = (⭐ applyData) => {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const sendRequest = ✨ useCallback(async (✨⭐ requestConfig) => {
setIsLoading(true);
setError(null);
try {
const response = await fetch(⭐ requestConfig.url, {
method: ⭐ requestConfig.method ? requestConfig.method : 'GET',
headers: ⭐ requestConfig.headers ? requestConfig.headers : {},
body: requestCofnig.body ? JSON.stringify(⭐ requestConfig.body) : null,
});
if (!response.ok) {
throw new Error('Request failed!');
}
const data = await response.json();
⭐ applyData(data);
} catch (err) {
setError(err.message || 'Something went wrong!');
}
setIsLoading(false);
}, [applyData]);
// requestConfig and applyData, which should be applied as dependencies
// are reference types
// -> ✨ use useCallback() in transformTasks!
// for requestConfig, we can use useMemo
// -> ✨ or use as a parameter for sendRequest
return {
isLoading,
error,
sendRequest,
};
}
export deault useHttp;
App.js - send GET request
// using custom hook
import useHttp from ~
function App() {
const [tasks, setTasks] = useState([]);
const transformTasks = ✨ useCallback(taskObj) => {
for (const taskKey in taskObj) {
loadedTasks.push({id: taskKey, text : taskObj[taskKey].text});
}
setTasks(loadedTasks);
}, []);
const { isLoading, error, sendRequest : fetchTasks } = useHttp(transformTasks);
useEffect(() => {
fetchTasks({url : "the api url for GET request"});
}, [fetchTasks]);
// if putting fetchTasks as dependency, it will create an infinite loop
// -> ✨ use useCallback() in sendRequest!
}
sending a POST request can be coded in a similar way