원문: https://medium.com/meliopayments/leave-useeffect-alone-d522a60bbbd4
부제: 리액트의 불필요한 리렌더링을 줄이기
저는 Melio에서 리액트 웹 애플리케이션을 개발하는 풀스택 개발자로서 프런트엔드 개발이 백엔드 개발만큼이나 복잡하다는 것을 몸소 경험했습니다. 프런트엔드 개발은 상태 관리, 반응성 보장, 성능 최적화 등의 복잡하고 어려운 과제를 갖고 있습니다.
모든 프런트엔드 프레임워크에는 내부 동작 방식, 어려운 과제, 고유한 특성이 있으며 리액트 또한 예외는 아닙니다. 유명한 useEffect 훅처럼 일부 메커니즘은 제대로 사용하려면 일정 수준의 이해가 필요합니다.
useEffect는 리액트에서 제공하는 가장 보편적으로 사용되는 훅 중 하나입니다. 이 훅은 데이터 가져오기, 구독, 직접 변경 등을 포함한 외부 요인/서비스와 컴포넌트를 동기화시킬 수 있지만, 아주 쉽게 남용되기도 합니다. 이 글에서는 모든 개발자가 피해야 하는 몇 가지 상황과 리액트 팀이 새로운 리액트 문서(react.dev)에서 제공하는 해결책에 대해 다뤄보겠습니다.
useEffect를 남용하지 마세요!
다음 예제에서는 useEffect 훅의 잘못된 사용으로 인해 발생하는 경쟁 상태(race condition)을 가정해 보겠습니다. 우리가 기대하는 동작은 마지막 request가 response를 업데이트 해야 한다는 것입니다.
// 🔴 마지막 요청에서 response 상태값을 저장한다는 것을 보장할 수 있나요?
function RaceConditionExample() {
const [counter, setCounter] = useState(0);
const [response, setResponse] = useState(0);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
const request = async (requestId) => {
setIsLoading(true);
await sleep(Math.random() * 3000);
setResponse(requestId);
setIsLoading(false);
};
request(counter);
}, [counter]);
const handleClick = () => {
setCounter((prev) => ++prev);
};
return (
<>
//....
<button onClick={handleClick}>Increment</button> //...
</>
);
}
예상과 다르게 동작합니다. 이전에 실행한 request가 response를 덮어서 저장하게 됩니다. (아래를 읽기 전에 이 코드펜에서 올바르게 수정해 보세요!)
새로운 리액트 문서 예시에 따르면 위의 경쟁 상태를 클린업 함수로 처리할 수 있습니다.
// ✅ 클린업 함수로 경쟁 상태를 처리합니다
useEffect(() => {
let ignore = false;
const request = async (requestId) => {
setIsLoading(true);
await sleep(Math.random() * 3000);
if (!ignore) {
setResponse(requestId);
setIsLoading(false);
}
};
request(counter);
return () => {
ignore = true;
};
}, [counter]);
기대한 바와 같이 올바르게 동작합니다.
다음 예제에서는 데이터를 잘못된 방향으로 전달했을 때 렌더링이 추가로 발생하는 경우에 대해 설명하겠습니다.
리액트의 데이터는 폭포수처럼 전달되어야 합니다.
잘못된 사용 1: 사용자가 클릭한 후 몇 번 렌더링 되나요?
function Parent() {
const [someState, setSomeState] = useState();
return <Child onChange={(...) => setSomeState(...)} />
}
function Child({ onChange }) {
const [isOn, setIsOn] = useState(false);
useEffect(() => {
// 🚨 추가적인 렌더링을 유발합니다
onChange(isOn);
}, [isOn, onChange]);
function handleClick() {
️⃣ // 클릭한 후에 첫 번째 렌더링을 일으킵니다
setIsOn(!isOn);
}
return <button onClick={handleClick}>Toggle</button>;
}
클릭 이벤트는 (첫 번째 렌더링을 만드는) 로컬 상태를 업데이트합니다. 이펙트가 실행 중이며 부모 컴포넌트가 제공하는 콜백을 호출하고, (두 번째 렌더링이 될) someState도 업데이트합니다.
이렇게 해결합니다.
function Parent() {
const [someState, setSomeState] = useState();
return <Child onChange={(...) => setSomeState(...)} />
}
function Child({ onChange }) {
const [isOn, setIsOn] = useState(false);
// ✅ 업데이트를 일으키는 이벤트 함수에서 모든 업데이트를 수행하는 것이 좋습니다
function handleClick() {
const newValue = !isOn;
setIsOn(newValue);
onChange(newValue);
}
return <button onClick={handleClick}>Toggle</button>;
}
useEffect에서 호출되는 onChange는 전혀 필요하지 않습니다. onClick 핸들러 내에서 간단히 호출할 수 있으며, 동일한 결과를 얻으면서도 렌더링을 한 번 줄입니다.
잘못된 사용 2: 데이터 흐름 체인을 망가뜨리기
function Parent() {
const [data, setData] = useState(null);
return <Child onFetched={setData} />;
}
// 🔴 Effect 내에서 부모에게 데이터를 전달하는 건 좋지 않습니다
function Child({ onFetched }) {
const data = useFetchData();
useEffect(() => {
if (data) {
// 🇮🇹 스파게티 코드를 만드는 건가요?
onFetched(data);
}
}, [onFetched, data]);
return <>{JSON.stringify(data)}</>;
}
데이터가 부모에서 자식 방향으로 흐르도록 유지해야 에러 추적, 유지보수, 디버깅 측면에서 더욱 유리합니다.
게다가 코드의 가독성을 높이고 따라 하기 쉽게 만들어 줍니다. 실제 프로덕트 코드의 양은 훨씬 더 많습니다. 따라서 코드가 복잡해질수록 어떤 컴포넌트가 콜백을 부모 컴포넌트에 전달하는지, 그리고 얼마나 잘못된 방향으로 가고 있는지를 추적하는 건 더욱 어려워집니다. 데이터의 '진실의 출처(source of truth)'를 이해하는 것 또한 어렵습니다.
부모 컴포넌트에서 상태를 관리하도록 해결합니다!
// 제안 #1 데이터를 가져오는 로직을 상위 컴포넌트에서 처리합니다
function Parent() {
const data = useFetchData();
// ✅ 올바른 방향으로 자식에게 데이터를 전달합니다
return <Child data={data} />;
}
function Child({ data }) {
return <>{JSON.stringify(data)}</>;
}
자식 컴포넌트에 데이터를 가져오는 로직을 유지할 수밖에 없다면, 별도의 useState 또는 useEffect를 정의하는 대신 부모에게 전달받은 핸들러를 사용하여 데이터와 상호작용 하는 것이 바람직합니다.
// 제안 #2 - onSuccess/onError 핸들러를 자식 컴포넌트에 전달합니다
function Parent() {
function handleSuccess = (data) => {
// 성공을 처리하는 로직
}
function handleError = (error) => {
// 실패를 처리하는 로직
toast(error.messasge)
}
// ✅ 올바른 방향으로 자식에게 데이터를 전달합니다
return <Child onSuccess={handleSuccess} onError={handleError} />;
}
function Child({ onSuccess, onError }) {
// ✅ 다른 이펙트는 관여하지 않고 데이터를 가져왔을 때 핸들러를 호출하는 훅을 사용하는 것이 좋습니다.
const mutate = useMutateData({ onSuccess, onError });
return ...;
}
그 친구 좀 내버려 두세요!
앱 런타임 중에 딱 한 번만 초기화를 실행하는 경우가 많습니다.
function App() {
useEffect(() => {
someOneTimeLogic();
}, []);
// ...
}
'someOneTimeLogic' 함수가 (인증 프로바이더와 같은) 무언가를 초기화하는 중이며 한 번만 실행해야 한다고 가정합니다.
이 경우에서 useEffect를 사용해서는 안 되는 몇 가지 이유를 생각해 보겠습니다.
대안 1. 이전에 마운트 되었는지 나타내는 최상위 플래그를 사용하기
let didInit = false;
function App() {
useEffect(() => {
if (!didInit) {
didInit = true;
// ✅ 앱 로드 시 한 번만 실행됩니다
someOneTimeLogic();
}
}, []);
// ...
}
대안 2. 앱이 렌더되기 전에 로직을 적용하기
if (typeof window !== "undefined") {
// ✅ 앱 로드 시 한 번만 실행됩니다
someOneTimeLogic();
}
function App() {
// ...
}
리액트 팀은 "언마운트 된 컴포넌트에서 리액트 상태 업데이트를 수행할 수 없습니다"라는 경고를 제거했으므로 이제 이를 두려워할 필요가 없습니다. 이 문제를 우회하면서 구현하는 것이 원래 문제보다 더 나쁜 결과를 초래할 수 있습니다!
이 경고는 제거되었습니다.
메모리 누수가 발생하지 않으며, 언마운트 된 컴포넌트에서 setState를 호출해도 에러가 발생하지 않습니다. 이러한 상황에서 setState를 막을 이유가 없습니다. 실제로 이를 피하려다 불필요한 useEffect를 추가하기도 합니다."
일반적인 우회 방법은 아래와 같았습니다.
const useMountedRef = () => {
const mounted = useRef(true);
useEffect(() => {
return () => {
mounted.current = false;
};
}, []);
return mounted;
};
const MyCompoenet = () => {
const [loading, setLoading] = useState(false);
const mountedRef = useMountedRef();
const handleDeleteBill = async (id) => {
setLoading(true);
await axios.delete(`/bill/${id}`);
// 🔴 언마운트된 컴포넌트에서 상태를 업데이트하지 않으려 했지만, 오히려 이 방법이 더 좋지 않습니다.
if (mountedRef.current) {
setLoading(false);
}
};
return (
<button onClick={handleDeleteBill} disabled={loading}>
Delete Bill
</button>
);
};
언마운트된 컴포넌트에서 상태의 업데이트를 피하지 말아야 하는 이유는 다음과 같습니다.
const MyCompoenet = () => {
const [loading, setLoading] = useState(false);
const handleDeleteBill = async (id) => {
setLoading(true);
await axios.delete(`/bill/${id}`);
// ✅ 상태를 업데이트하는 걸 두려워하지 마세요.
setLoading(false);
};
return (
<button onClick={handleDeleteBill} disabled={loading}>
Delete Bill
</button>
);
};
읽어주셔서 감사합니다. useEffect를 남발하면 안된다는 점을 꼭 기억해 주세요!
I like the way you made this article. Short but juicy. Thanks for sharing!
https://www.ehallpasses.com
With challenges like state management and performance optimization, each front-end framework, including React, poses unique hurdles. The popular useEffect hook requires careful understanding to avoid misuse. Just like in https://geometrydashjump.com/ where precision and timing matter, mastering React's features is essential for smooth development.
The woman performs all the tasks you would like her to perform when she gets there. They will provide you with massages in your bedroom and then spend the night with you should you want to. Charges for out-calls are higher than those for in-call service as transport costs, as well as other expenses will be included in the total cost of the services.
https://www.nancymittal.in
https://www.nancymittal.in/call-girls-dehradun.html
https://www.nancymittal.in/call-girls-mussoorie.html
https://www.nancymittal.in/call-girls-rishikesh.html
https://www.nancymittal.in/call-girls-dhanaulti.html
https://www.nancymittal.in/call-girls-haridwar.html
https://www.nancymittal.in/call-girls-haldwani.html
https://www.nancymittal.in/call-girls-ramnagar.html
https://www.nancymittal.in/call-girls-rudrapur.html
https://www.nancymittal.in/call-girls-bhimtal.html
https://www.nancymittal.in/call-girls-nainital.html
https://www.nancymittal.in/call-girls-delhi.html
https://www.nancymittal.in/call-girls-gurgaon.html
https://www.nancymittal.in/call-girls-udaipur.html
https://www.nancymittal.in/call-girls-raipur.html
https://www.nancymittal.in/call-girls-lucknow.html
https://www.nancymittal.in/call-girls-aerocity.html
https://www.nancymittal.in/call-girls-jaipur.html
https://www.nancymittal.in/call-girls-jodhpur.html
https://www.nancymittal.in/call-girls-kishangarh.html
https://www.nancymittal.in/call-girls-pushkar.html
https://www.nancymittal.in/call-girls-nasirabad.html
You can also enjoy her company more as you are not rushed. You can find a partner for your bedroom by visiting the profiles of escorts from Goa who cater to the sexy desires of wealthy customers in different parts of India.
https://www.juhimittal.com
https://www.juhimittal.com/location/panaji-escorts.html
https://www.juhimittal.com/location/calangute-beach-escorts.html
https://www.juhimittal.com/location/baga-beach-escorts.html
https://www.juhimittal.com/location/anjuna-beach-escorts.html
https://www.juhimittal.com/location/colva-beach-escorts.html
https://www.juhimittal.com/location/candolim-beach-escorts.html
We offer independent call girls for erotic massaging in Udaipur. In any of the top-rated hotels, you can enjoy an erotic masseuse with striptease and foreplay. You will be in ecstasy when they massage your soft boobs into your face.
https://www.anisharoy.com
https://www.anisharoy.com/udaipur-escort-service.html
https://www.anisharoy.com/ahmedabad-escort-service.html
https://www.anisharoy.com/ajmer-escort-service.html
https://www.anisharoy.com/dehradun-escort-service.html
https://www.anisharoy.com/jaipur-escort-service.html
https://www.anisharoy.com/jodhpur-escort-service.html
A lot of times, we are just looking to impress our colleagues and business associates with an attractive companion that can boost your intelligence and add positive energy to your attitude. They listened to you in a crowd of people to eventually achieve your Nainitals in life. Girls like us are gifted in that they don't make you feel like a burden before anyone else; that makes you feel proud of their achievements.
https://www.juhioberoi.com
https://www.juhioberoi.com/haldwani-escort-service-call-girls.html
https://www.juhioberoi.com/ramnagar-escort-service-call-girls.html
https://www.juhioberoi.com/bhimtal-escort-service-call-girls.html
https://www.juhioberoi.com/rudrapur-escort-service-call-girls.html
https://www.juhioberoi.com/jaipur-call-girl-escort.html
https://www.juhioberoi.com/ajmer-call-girl-escort.html
https://www.juhioberoi.com/pushkar-call-girl-escort.html
https://www.juhioberoi.com/kishangarh-call-girl-escort.html
https://www.juhioberoi.com/agra-call-girl-escort.html
https://www.juhioberoi.com/nasirabad-call-girl-escort.html
https://www.juhioberoi.com/beawar-call-girl-escort.html
https://www.juhioberoi.com/ahmedabad-call-girl-escort.html
https://www.juhioberoi.com/amritsar-call-girl-escort.html
https://www.juhioberoi.com/andheri-call-girl-escort.html
https://www.juhioberoi.com/bangalore-call-girl-escort.html
https://www.juhioberoi.com/goa-call-girl-escort.html
https://www.juhioberoi.com/dehradun-call-girl-escort.html
https://www.juhioberoi.com/chennai-call-girl-escort.html
https://www.juhioberoi.com/bhopal-call-girl-escort.html
https://www.juhioberoi.com/gurgaon-call-girl-escort.html
https://www.juhioberoi.com/guwahati-call-girl-escort.html
https://www.juhioberoi.com/haridwar-call-girl-escort.html
https://www.juhioberoi.com/indore-call-girl-escort.html
https://www.juhioberoi.com/kota-call-girl-escort.html
https://www.juhioberoi.com/kolkata-call-girl-escort.html
https://www.juhioberoi.com/kanpur-call-girl-escort.html
https://www.juhioberoi.com/jodhpur-call-girl-escort.html
https://www.juhioberoi.com/lucknow-call-girl-escort.html
https://www.juhioberoi.com/manali-call-girl-escort.html
https://www.juhioberoi.com/mohali-call-girl-escort.html
https://www.juhioberoi.com/mussoorie-call-girl-escort.html
https://www.juhioberoi.com/rishikesh-call-girl-escort.html
https://www.juhioberoi.com/rajkot-call-girl-escort.html
https://www.juhioberoi.com/pune-call-girl-escort.html
https://www.juhioberoi.com/nagpur-call-girl-escort.html
https://www.juhioberoi.com/shimla-call-girl-escort.html
https://www.juhioberoi.com/surat-call-girl-escort.html
https://www.juhioberoi.com/thane-call-girl-escort.html
https://www.juhioberoi.com/udaipur-call-girl-escort.html
https://www.juhioberoi.com/chandigarh-call-girl-escort.html
https://www.juhioberoi.com/navi-mumbai-call-girl-escort.html
https://www.juhioberoi.com/zirakpur-call-girl-escort.html
https://www.juhioberoi.com/varanasi-call-girl-escort.html
https://www.juhioberoi.com/ghaziabad-call-girl-escort.html
https://www.juhioberoi.com/hyderabad-call-girl-escort.html
https://www.juhioberoi.com/aerocity-call-girl-escort.html
https://www.juhioberoi.com/noida-call-girl-escort.html
https://www.juhioberoi.com/dwarka-call-girl-escort.html
https://www.juhioberoi.com/gwalior-call-girl-escort.html
https://www.juhioberoi.com/nashik-call-girl-escort.html
https://www.juhioberoi.com/delhi-call-girl-escort.html
https://www.juhioberoi.com/patna-call-girl-escort.html
https://www.juhioberoi.com/roorkee-call-girl-escort.html
https://www.juhioberoi.com/mumbai-call-girl-escort.html
https://www.juhioberoi.com/raipur-call-girl-escort.html
We will share just one step with you: call our number provided in this article. Then, you will have a good idea of everything that you would like to know. Therefore, make use of the booking process and take advantage of the escorting services in Jaipur.
https://www.jaipurescorts.org
https://www.jaipurescorts.org/call-girls-service-jaipur.html
https://www.jaipurescorts.org/raja-park-escorts.html
https://www.jaipurescorts.org/bani-park-escorts-services.html
https://www.jaipurescorts.org/tonk-road-escorts-services.html
https://www.jaipurescorts.org/durgapura-escorts-services.html
https://www.jaipurescorts.org/jagatpura-escorts-services.html
https://www.jaipurescorts.org/gopalpura-escorts-services.html
https://www.jaipurescorts.org/mansarovar-escorts-services.html
https://www.jaipurescorts.org/civil-lines-escorts-services.html
https://www.jaipurescorts.org/sangner-escorts-services.html
https://www.jaipurescorts.org/bhankrota-call-girls-escorts-services.html
https://www.jaipurescorts.org/ajmer-road-call-girls-escorts-services.html
https://www.jaipurescorts.org/chitrakoot-call-girls-escorts-services.html
https://www.jaipurescorts.org/jhotwara-call-girls-escorts-services.html
https://www.jaipurescorts.org/bajaj-nagar-call-girls-escorts-services.html
https://www.jaipurescorts.org/adarsh-nagar-call-girls-escorts-services.html
https://www.jaipurescorts.org/pratap-nagar-call-girls-escorts-services.html
https://www.jaipurescorts.org/mahesh-nagar-call-girls-escorts-services.html
https://www.jaipurescorts.org/shyam-nagar-call-girls-escorts-services.html
https://www.jaipurescorts.org/nirman-nagar-call-girls-escorts-services.html
https://www.jaipurescorts.org/malviya-nagar-escorts-services.html
https://www.jaipurescorts.org/vaishali-nagar-escorts-services.html
https://www.jaipurescorts.org/sodala-call-girls-escorts-services.html
https://www.jaipurescorts.org/sindhi-camp-call-girls-escorts-services.html
https://www.jaipurescorts.org/narayan-vihar-call-girls-escorts-services.html
https://www.jaipurescorts.org/bais-godam-call-girls-escorts-services.html
https://www.jaipurescorts.org/vivek-vihar-call-girls-escorts-services.html
https://www.jaipurescorts.org/khatipura-call-girls-escorts-services.html
https://www.jaipurescorts.org/ajmer-escort-service.html
https://www.jaipurescorts.org/jaisalmer-escort-service.html
https://www.jaipurescorts.org/udaipur-escort-service.html
https://www.jaipurescorts.org/jodhpur-escort-service.html
https://www.jaipurescorts.org/pushkar-escort-service.html
https://www.jaipurescorts.org/beawar-escort-service.html
https://www.jaipurescorts.org/kishangarh-escort-service.html
This weekend can benefit the most from the extra time you spend in Dehradun with gorgeous young women available 24 hours a day. Your week's ending should be beautiful and supple, which helps you forget any weight or issues.
https://www.dehradunescortsagency.in
https://www.dehradunescortsagency.in/dehradun-call-girls.html
https://www.dehradunescortsagency.in/haridwar-call-girl-escort.html
https://www.dehradunescortsagency.in/rishikesh-call-girl-escort.html
https://www.dehradunescortsagency.in/mussoorie-call-girl-escort.html
https://www.dehradunescortsagency.in/haldwani-escort-service-call-girls.html
https://www.dehradunescortsagency.in/ramnagar-escort-service-call-girls.html
https://www.dehradunescortsagency.in/rudrapur-escort-service-call-girls.html
https://www.dehradunescortsagency.in/bhimtal-escort-service-call-girls.html
항상 쓰는 useEffect에 대해서 새로 알아가는 부분도 있고 제가 잘 쓰고 있다고 느꼈던 부분도 보이네요. 감사합니다