해결된 질문
작성
·
50
0
아래 질문들을 보던 중 Editor 부분이 리렌더링 된다는 글을 보고 제 화면도 확인한 결과 리렌더링 된 걸 확인해서 Editor.jsx 또한 아래와 같이 memo메서드를 감싸줬더니 리렌더링 되지 않는 것을 확인했습니다.
import "./Editor.css";
import { useState, useRef, memo } from "react";
const Editor = ({ onCreate }) => {
const [content, setContent] = useState("");
const contentRef = useRef();
const onChangeContent = (e) => {
setContent(e.target.value);
};
const onKeyDown = (e) => {
if (e.keyCode === 13) {
onSubmit();
}
};
const onSubmit = () => {
if (content.trim() === "") {
contentRef.current.focus();
return;
}
onCreate(content.trim());
setContent("");
};
return (
<div className="Editor">
<input
ref={contentRef}
value={content}
onKeyDown={onKeyDown}
onChange={onChangeContent}
placeholder="새로운 Todo..."
/>
<button onClick={onSubmit}>추가</button>
</div>
);
};
export default memo(Editor);
Editor.jsx의 props가 onCreate 메서드인데 이를 App.jsx에서 useCallback 처리를 해줘서
그냥 export default memo(Editor); 을 해줘도 리렌더링 방지가 가능했던 것인지 궁금해서 질문 남깁니다!
App.jsx 코드입니다!
import "./App.css";
import { useState, useRef, useReducer, useCallback } from "react";
import Header from "./components/Header";
import Editor from "./components/Editor";
import List from "./components/List";
const mockData = [
{
id: 0,
isDone: false,
content: "운동하기",
date: new Date().getTime(),
},
{
id: 1,
isDone: false,
content: "풋살하기",
date: new Date().getTime(),
},
{
id: 2,
isDone: false,
content: "게임하기",
date: new Date().getTime(),
},
];
function reducer(state, action) {
switch (action.type) {
case "CREATE":
return [action.data, ...state];
case "UPDATE":
return state.map((item) =>
item.id === action.targetId
? { ...item, isDone: !item.isDone }
: item
);
case "DELETE":
return state.filter((item) => item.id !== action.targetId);
default:
return state;
}
}
function App() {
const [todos, dispatch] = useReducer(reducer, mockData);
const idRef = useRef(3);
const onCreate = useCallback((content) => {
dispatch({
type: "CREATE",
data: {
id: idRef.current++,
isDone: false,
content: content,
date: new Date().getTime(),
},
});
}, []);
const onUpdate = useCallback((targetId) => {
dispatch({
type: "UPDATE",
targetId: targetId,
});
}, []);
const onDelete = useCallback((targetId) => {
dispatch({
type: "DELETE",
targetId: targetId,
});
}, []);
return (
<div className="App">
<Header />
<Editor onCreate={onCreate} />
<List todos={todos} onUpdate={onUpdate} onDelete={onDelete} />
</div>
);
}
export default App;
답변 2
1
안녕하세요 이정환입니다.
네 맞습니다. 상황을 구체적으로 설명드리면 다음과 같습니다.
Editor 컴포넌트는 아무런 최적화도 되어 있지 않은 상황이기에 부모 컴포넌트인 App 컴포넌트가 리렌더링 되면 동시에 리렌더링 됩니다.
위 이야기는 바꿔 말하면 새로운 Todo가 추가되거나, 기존 Todo가 수정되어 App 컴포넌트의 State가 변경될 경우 Editor 컴포넌트도 리렌더링 된다는 말 입니다.
이때 Editor 컴포넌트에 React.memo를 적용하면 더 이상 App 컴포넌트의 리렌더링에 Editor가 동시에 리렌더링 되지 않습니다. 그 이유는 다음과 같습니다.
React.memo는 Prosp로 제공받는 값이 변경되지 않으면 컴포넌트를 리렌더링 하지 않도록 최적화합니다.
현재 Editor 컴포넌트가 제공받는 onCreate Props는 App 컴포넌트에서 이미 useCallback을 이용해 재생성되지 않도록 최적화 해 두었습니다.
결론적으로 App 컴포넌트의 State가 수정되어도 Editor 컴포넌트에게 제공되는 Props의 값은 변경되지 않습니다.
그런데 여기서 한가지 주의해야 할 점은 바로 과도한 최적화는 오히려 독이 될 수도 있다는 사실입니다.
Editor 컴포넌트는 아주 단순한 구성으로 이루어져 있습니다. <input>과 <button>만 존재하죠, 그리고 보통 이렇게 단순하고 가벼운 컴포넌트는 최적화 대상으로 삼지 않습니다.
최적화는 강의에서 말씀드렸듯 꼭 필요한 부분에만 적절히 적용하는걸 권장해드리고 있기 때문에 요런 점도 함께 고려해보시면 좋을 것 같습니다 😃
0
안녕하세요, 인프런 AI 인턴입니다. kwon님이 질문하신 것처럼 React.memo
를 사용하면 컴포넌트가 동일한 props를 받을 경우 리렌더링을 방지할 수 있습니다. memo
함수는 해당 컴포넌트가 받는 props가 변경되지 않는 한, 다시 렌더링하지 않도록 해주기 때문에 컴포넌트의 성능을 최적화하는 데 효과적입니다.
App
컴포넌트의 onCreate
함수를 useCallback
을 사용하여 메모이제이션하셨습니다. useCallback
은 함수의 의존성 배열이 변경되지 않는 한, 같은 함수 객체를 반환하므로, Editor
컴포넌트에 주입되는 onCreate
prop 또한 동일한 참조를 유지하게 됩니다. 이렇게 함으로써 memo
로 감싸진 Editor
컴포넌트는 onCreate
prop이 변경되지 않았다고 판단하여 불필요한 리렌더링을 피할 수 있습니다.
이와 관련된 추가 설명 또는 사례를 참고하려면, 다음의 유사한 질문과 답변을 확인해볼 수 있습니다:
React.memo
와 useCallback
의 조합으로 최적화를 시도했습니다.Checkbox를 누르는데 왜 Editor가 리렌더링되나요?
React.memo
와 prop 변경에 대한 부분이 주로 다뤄집니다.위 답변들을 통해 리렌더링 최적화에 대한 다양한 접근 방식과 해결 방법을 참고하실 수 있습니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
감사합니다 강사님:)