-
관련 PR관련 내용 논의 디스코드https://discord.com/channels/1386597391473446923/1428598746719064115/1441347779875049605 문제 상황
useEffect(() => {
if (!file) {
setPreview(null) // Error!
return;
}
}, []);[{
"resource": "...",
"owner": "eslint11",
"code": "react-hooks/set-state-in-effect",
"severity": 8,
"message": "Error: Calling setState synchronously within an effect can trigger cascading renders\n\nEffects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:\n* Update external systems with the latest state from React.\n* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\nCalling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect).\n\n/Users/ahreum/Documents/myfolder/coding/lecture/codeit_sprint/taskify-frontend/src/components/common/ImageUploader.tsx:49:5\n 47 |\n 48 | const url = URL.createObjectURL(value);\n> 49 | setPreview(url);\n | ^^^^^^^^^^ Avoid calling setState() directly within an effect\n 50 |\n 51 | return () => {\n 52 | URL.revokeObjectURL(url);",
"source": "eslint",
"startLineNumber": 49,
"startColumn": 5,
"endLineNumber": 49,
"endColumn": 15,
"origin": "extHost1"
}]린트 설정 중 react-hooks/set-state-in-effect가 활성화 되어있어서 이 부분을 해결하려고 찾아보니 비동기적으로 setState를 실행할 수 있게 하면 된다고 해서 useEffect(() => {
const timeout = setTimeout(() => {
if (!file) {
setPreview(null);
return;
}
const url = URL.createObjectURL(file);
setPreview(url);
}, 0);
return () => clearTimeout(timeout);
}, [file]); |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 9 replies
-
|
추가적으로 관련 내용을 찾아보면서 동기적 setState, cascading render라는 개념을 알게되었는데..
|
Beta Was this translation helpful? Give feedback.
-
|
라이브코딩떄도 함께 이야기 했지만 지금 같은경우는 파일을 업로드하면 렌더링을 해줘야 변경된 파일이 적용되 보일텐데요 다만
preview 값은 file 값에 따라 변하는 의존값이기에 아마 린트에서 에러를 띄워준것도 useEffect 내부에서 setState 를 사용하지 마라가 아니라 |
Beta Was this translation helpful? Give feedback.
-
|
정리하면 useEffect 내부에서 setState 를 처리해도 됩니당 :) 다만 useEffect 의 deps 에있는 의존성 변수와 다시한번더 해당 state 가 setState 쓰여도 되는지 의심해 봐야합니다 이해가 안되시거나 잘못 말씀드린것이라면 말씀해주세요~ |
Beta Was this translation helpful? Give feedback.
-
|
아래내용을 읽어보시면 조금 도움이 되실것같습니다 공식문서 Effect가 필요하지 않은 경우
|
Beta Was this translation helpful? Give feedback.
-
해결 방안
useEffect(() => {
if (!preview) return;
return () => {
URL.revokeObjectURL(preview);
};
}, [preview]);file이 바뀌면 preview도 새 문자열이 되고 이전 preview는 cleanup에 의해 revoke |
Beta Was this translation helpful? Give feedback.




라이브코딩떄도 함께 이야기 했지만
useState를 사용하실떄는 항상 렌더링 이 필요한 ,렌더링을 일으켜야할 상태가 필요할떄 사용하셔야 합니다
지금 같은경우는 파일을 업로드하면 렌더링을 해줘야 변경된 파일이 적용되 보일텐데요
그래서
const [file, setFile] = useState<File | null>(null);인경우는 분명히 렌더할 필요가 있어보입니다setFile 을 쓰는시점을 파일을 변경할태이고 그에따라 file 값을 변경시켜 컴포넌트가 변경된 file 적용되도록 렌더링 시켜야겠죵
다만
const [preview, setPreview] = useState<string | null>(null);같은 경우에는 useState 로 선언할 이유가 보이지않습니다preview 값에 따라 렌더가 로직상 필요해보이지않습니다
preview 값은 file 값에 따라 변하는 의존값이기에
const preview = file ? URL.createObjectURL(file) : null;선언 해주면 될것같습니다 file 변할때마다 변경되야 하는값이니까요아마 린트에서 에러를 띄워준것도 useEffect 내부에서 setState 를 사용하지 마라가 아니라
"너 굳이 왜 deps 에있는 file 에따라 변하는 변수 (preview) 를 useState 로 선언해서 effect 내부에서 호출해 그럼 무한루프 돌수도있을껄 ?" …