본문 바로가기
꼬리에 꼬리를 무는 코딩

2022.09.29 꼬꼬코 React.memo 를 사용한 컴포넌트 성능 최적화

by 치우치지않는 2022. 9. 29.

1. React.memo 란? 

컴포넌트의 props가 바뀌지 않았다면, 리렌더링하지 않도록 설정하는 것! 

2. React.memo 의 사용법 

컴포넌트를 만들고 나서 감싸주기만 하면? 끝! 

const TodoListItem = ({ todo, onRemove, onToggle }) => {
	(...)
};

export default React.memo(TodoListItem);

-> todo, onRemove, onToggle 의 값이 바뀌지 않는 한, TodoListItem 은 리렌더링되지 않는다. 

 

But,, 여기서 끝이 난 게 아니다. onRemove 와 onToggle 함수는 배열 상태를 업데이트하는 과정에서 최신 상태의 todos 를 참조하기 때문에,  만약 todos 배열이 업데이트될 경우, onRemove 와 onToggle 함수가 계속 호출되게 된다. 그럼 이렇게 함수가 계속 만들어지는 상황을 방지하려면 어떻게 해야할까? 

3-1. useState 의 함수형 업데이트 기능을 사용하기 

SetTodos 를 사용할 때 새로운 상태를 파라미터로 넣는 대신, 상태 업데이트를 어떻게 할지 정의해 주는 업데이트 함수를 넣을 수도 있다. 이를 함수형 업데이트라고 부른다. 

const [number, setNumber] = useState(0); 
const onIncrease = useCallback(
	() => setNumber(prevNumber => prevNumber + 1), // setNumber(number + 1) 처럼 상태를 넣는 것이 아니라, 업데이트 함수를 넣어주자.
    [],
);

3-2. useReducer 사용하기 

import {useReducer} from 'react';

function todoReducer { todos, action } {
	switch(action.type) {
    	case 'INSERT': 
        return todos.concat(action.todo);
        case 'REMOVE': 
        return todos.filter(todo => ) 
        case 'TOGGLE': 
        return todos.map(todo => 
        	todo. id === action.id ? {...todo, checked: !todo.checked } : todo, 
        );
        default: 
        	return todos; 
    }
}

const App = () => {
	const [todos, dispatch] = useReducer(todoReducer, undefined, createBulkTodos); 
    const nextId = useRef(2501); 
    
    const onInsert = useCallback(text => {
    	const todo = {
        id : nextId.current,
        text,
        checked: false, 
        };
        dispatch({type: 'INSERT', todo });
        nextId.current += 1;
    }, []);
    
    const onRemove = useCallback(id => {
    	dispatch({ type: 'REMOVE', id});
    }, []);
    
    const onToggle = useCallback(id => {
    	dispatch({type: 'TOGGLE', id});
    }, []);
    
    return (
    	<TodoTemplate> 
        	<TodoInsert onInsert = {onInsert} />
            <TodoList todos = {todos} onRemove = {onRemove} onToggle={onToggle} />
        </TodoTemplate>
    );
    
};

export default App;

useReducer 를 사용할 때는 원래 두 번째 파라미터에 초기 상태를 넣엊어야 하지만, 만약 두 번째 파라미터에 undefined 를 넣어주고 세 번째 파라미터에 초기 상태를 리턴하는 함수를 넣으면, 컴포넌트가 맨 처음 렌더링할 때만 초기 함수가 호출되게 된다. 

 

++ 리스트 컴포넌트 성능 최적화

1. 리스트에 관련된 컴포넌트를 최적화할 때는 리스트 아이템과 리스트, 두 가지 컴포넌트를 최적화해 주어야 한다. 내부 데이터가 100개를 넘지 않거나 업데이트가 자주 발생하지 않는다면, 이런 최적화 작업을 반드시 해줄 필요는 없다. 

TodoList.js 

import React from 'react';
import TodoListItem from './TodoListItem';
import './TodoList.css';

const TodoList = ({todos, onRemove, onToggle}) => {
	return (...);
};

export default React.memo(TodoList);

 

댓글