리액트로 프로젝트를 생성하여 개발하는 과정 중 리액트의 필수 문법 및 기초적인 부분, 심화 과정 등을 정리한 문서입니다. 정리한 부분에는 제가 이해하는 관점에서만 정리를 하였기 때문에 초점은 보여주는 형식이 아닌 제가 필요할 때 사용하려는 목적이 담겨져 있습니다. 전 시간에서는 useCallback 과 같이 React.memo를 사용하여 컴포넌트 리렌더링을 방지해보았습니다. useCallback과 React.memo를 같이 이용하는 예제를 이번에도 해볼 예정입니다. 내용은 전시간이랑 똑같지만 한번 더 복습하는 방향으로 설정하였습니다.
현재 정리부터는 소스코드를 제공할 예정입니다. 제공하는 소스코드를 이용하여 따라하실 수 있고 개념을 확실히 잡을 꺼 같아서 올리게 되었습니다. 소스코드 자료는 아래 링크를 참고해주세요.
https://github.com/libtv/React_Note/tree/master/13.%20react_memo
그러면 React.memo의 기초와 사용법 에 대해 배워보도록 합시다.
# Contents
- 사용하는 이유
- React.memo 기초와 사용법
# 사용하는 이유
컴포넌트의 props 가 바뀌지 않았다면, 리렌더링을 방지하여 컴포넌트의 리렌더링 성능 최적화를 해줄 수 있는 React.memo 라는 함수에 대해서 알아보겠습니다. 이 함수를 사용한다면 컴포넌트에서 리렌더링이 필요한 상황에서만 리렌더링을 하도록 설정할 수 있습니다. 이 함수는 useCallback과 같이 사용하면 더욱 좋다고 들었습니다.
우선, 구글에 React DevTools 를 검색해서 크롬 웹스토어에 들어간뒤, 크롬 확장 프로그램을 설치해주세요. 링크
그리고 렌더링 되는 컴포넌트를 확인하기 위하여 아래 설정을 참고하여주시기 바랍니다. 이 설정을 통해 우리는 어떠한 컴포넌트가 렌더링 되고 있는지를 확인할 수 있습니다.
그리고 아래와 같이 Input 박스 안에 텍스트를 넣게 되면 UserList들도 같이 변하게 됨을 확인할 수 있습니다. APP.js 의 CreateUser.js 의 onChange 메소드를 통해 useState를 불러오게 되고, 그에 따라 모든 App.js 컴포넌트들이 리랜더링 되었음을 아래 그림을 통해 확인할 수 있었습니다.
이제부터는 이것의 해결방법인 React.memo을 소개할 것입니다.
# React.memo 기초와 사용법
useCallback를 사용하기 위해서는 다음과 같은 구문을 사용해야 합니다.
import react from "react";
React.memo() 는 다음과 같습니다.
- React.memo()안에 컴포넌트(여기서는 함수)를 인자로 넣는다.
구문은 다음과 같습니다.
React.memo(컴포넌트)
아래 코드를 통해 React.memo를 확인해보세요. UserList.js
import react, { useEffect } from "react";
function UserList({ users, onToggle, onDelete }) {
return (
<div>
{users.map((user) => {
return <UserInfo user={user} onToggle={onToggle} onDelete={onDelete} />;
})}
</div>
);
}
function UserInfo({ user, onToggle, onDelete }) {
useEffect(() => {
console.log("user 값이 설정됨");
console.log(user);
return () => {
console.log("user 가 바뀌기 전..");
console.log(user);
};
}, [user]);
return (
<div>
<h2>
<b
style={{
backgroundColor: user.active ? "tomato" : "white",
}}
onClick={() => {
return onToggle(user.id);
}}
>
{user.id}
</b>{" "}
{user.name} {user.email}{" "}
<button
onClick={() => {
return onDelete(user.id);
}}
>
삭제
</button>
</h2>
</div>
);
}
export default react.memo(UserList);
아래 코드는 React.memo 함수를 사용하였습니다. 이렇게 React 컴포넌트 함수를 React.memo() 함수로 감싸주면 해당 컴포넌트 함수는 props 값이 변경되지 않는 한 다시 호출되지 않습니다. 아까와 마찬가지로 컴포넌트를 랜더링 시키기 위하여 Input 박스에 글자를 넣어보겠습니다.
결과 값은 아래와 같습니다.
분명 React.memo() 를 사용하여 UserList 의 컴포넌트들은 리랜더링하지 않음이라고 하였는데 리랜더링이 되고 있습니다. 그 이유는 함수가 다시 사용되기 때문에 리랜더링이 되기 때문인데요. React.memo를 사용할 때 리랜더링을 방지하기 위해 같이 사용하는 함수인 useCallback 을 사용하여 아래처럼 처리하면 리랜더링을 방지할 수 있습니다.
다음은 App.js 의 useCallback을 사용한 코드입니다.
import "./App.css";
import react, { useRef, useState, useMemo, useEffect, useCallback } from "react";
import UserList from "./UserList.js";
import CreateUser from "./CreateUser";
import MyRoom from "./MyRoom";
function App() {
const [input, setInputs] = useState({
name: "",
email: "",
});
const { name, email } = input;
const [users, setUsers] = useState([
{ id: 0, name: "John", email: "john@gmail.com", active: true },
{ id: 1, name: "Smith", email: "smith@gmail.com", active: false },
{ id: 2, name: "Park", email: "park@gmail.com", active: false },
{ id: 3, name: "Kim", email: "kim@gmail.com", active: false },
]);
var nextId = useRef(5);
var count = useMemo(() => countActiveUsers(users), users);
const onChangeCallback = useCallback(
(e) => {
onChange(e);
},
[input]
);
const onClickCallback = useCallback(() => {
onClick();
}, [users]);
const onToggleCallback = useCallback(
(userId) => {
onToggle(userId);
},
[users]
);
const onDeleteCallback = useCallback(
(userId) => {
onDelete(userId);
},
[users]
);
return (
<div>
<CreateUser name={name} email={email} onChange={onChangeCallback} onClick={onClickCallback} />
<UserList users={users} onToggle={onToggleCallback} onDelete={onDeleteCallback} />
<div>활성화된 사용자 수 : {count}</div>
</div>
);
function onChange(e) {
var { name, value } = e.target;
setInputs({ ...input, [name]: value });
}
function onClick() {
console.log("onClick 이 호출되었습니다.");
setUsers([...users, { id: nextId.current++, name, email, active: false }]);
}
function onToggle(userId) {
setUsers(
users.map((user) => {
return userId === user.id ? { ...user, active: true } : user;
})
);
}
function onDelete(userId) {
var newArr = [];
users.map((user) => {
return user.id !== userId ? newArr.push(user) : "";
});
setUsers([...newArr]);
}
function countActiveUsers(users) {
console.log("활성 사용자 수를 세는중...");
var s = users.filter((user) => {
return user.active == true;
});
return s.length;
}
}
export default App;
결과 값은 아래와 같습니다.
이렇게 해서 useCallback과 React.memo를 사용한 결과물을 획득하였습니다. 리액트를 사용하는 이유는 컴포넌트 단위로 개발할 수 있기 때문에 협업에 아주 많이 사용하는 것으로 알고 있습니다. 하지만 그에 반해 성능이 낮아지게 된다면 아주 큰 에로사항이라고 생각합니다.
리액트의 Hook을 통하여 리팩토링과 성능을 올리는 것이 리액트 개발자의 역할이라고 생각합니다.
'오픈소스 > 노드' 카테고리의 다른 글
[Node] React 정리(15) - useReducer를 사용한 코드 예제 (0) | 2021.10.19 |
---|---|
[Node] React 정리(14) - useReducer를 사용하여 상태 업데이트 분리 (0) | 2021.10.19 |
[Node] React 정리(12) - useCallback을 사용하여 성능 최적화 하기 (0) | 2021.10.18 |
[Node] React 정리(11) - useMemo를 사용하여 연산한 값 재사용하기 (0) | 2021.10.18 |
[Node] React 정리(10) - useEffect를 사용하여 마운트/언마운트/업데이트 (0) | 2021.10.18 |