11. 컴포넌트 성능 최적화

hey hey·2021년 12월 13일
0

리액트 배우기

목록 보기
15/26
post-thumbnail

많은 데이터 렌더링하기

App.js

function createBulkTodos(){
  const array = []
  for (let i=1; i<=2500;i++){
    array.push({
      id:i,
      text:`할 일${i}`,
      checked:false
    })
  }
  return array
}

const App = ()=>{  
  const [todos,setTodos] = useState(createBulkTodos)
...}

useState의 기본값에 함수를 넣어주기 2500개 추가해주기

→ 확실히 성능이 느려진다.

React DevTools (모니터링)

리액트 개발자 도구에 Profiler를 사용하면 자세하게 알 수 있다.

느려지는 원인

  1. 자신이 전달받은 props가 변경될 대
  2. 자신의 state가 바뀔 때
  3. 부모 컴포넌트가 리렌더링 될 때
  4. forceUpdate 함수가 실행될 때

현재는 state 하나를 변경했는데 전체가 리렌더링 되어서 느려졌다.

React.memo 사용하기

  • 사용법 : 컴포넌트를 만들고 감싸주기만 하면 된다?
  • TodoListItem은 todo,onRemove,onToggle이 바뀌지 않으면 리렌더링 안한다.

TodoListItem.js

 ...
export default React.memo(TodoListItem)

memo를 써도 최적화가 끝난게 아니다

todos 배열이 업데이트되면 onRemove와 onToggle 함수도 바뀌기 때문이다.

→ 함수가 계속 만들어지는 상황을 방지해야 한다.

  1. useState의 함수형 업데이트 기능 사용
  2. useReducer 사용

useState의 함수형 업데이트

기존의 setTodos 함수를 사용할 때는 새로운 상태를 파라미터로 넣어 주었다.

setTodos를 사용할 때 새로운 상태를 파라미터로 넣는 대신

상태 업데이트를 어떻게 정의해 주는 업데이트 함수를 넣을 수 있다.

  • 사용법 : setTodos를 사용하는 곳에 todos⇒를 넣고 , useCallback(()⇒{},[todos])[todos] 를 비워주면 된다

App.js

const onRemove = useCallback(
    id =>{
      setTodos(todos.filter(todo=> todo.id!== id))
    },
    [todos]
  )
const onRemove = useCallback(
    id =>{
      setTodos(todos=>todos.filter(todo=> todo.id!== id))
    },[])

const onToggle = useCallback(
    id=>{
      setTodos( todos=>
        todos.map(todo=>
          todo.id === id ? {...todo,checked:!todo.checked} : todo),
      )
    },[]
  )
const onInsert = useCallback(
    text=>{
      const todo = {
        id:nextId.current,
        text,
        checked:false
      };
      setTodos(todos=>todos.concat(todo))
      nextId.current+=1;
    },[]
  )

useReducer 사용

  • 기존 코드를 많이 고쳐야 하지만, 상태를 업데이트하는 로직을 모아 컴포넌트 밖에 둘수 있다.
import React,{useReducer,useCallback,useRef} from 'react'

function createBulkTodos(){
  const array = []
  for (let i=1; i<=2500;i++){
    array.push({
      id:i,
      text:`할 일${i}`,
      checked:false
    })
  }
  return array
}
function todoReducer(todos,action){
  switch (action.type){
    case 'INSERT':
      return todos.concat(action.todo)
    case 'REMOVE':
      return todos.filter(todo=>todo.id!==action.id)
    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 onRemove = useCallback(
    id =>{
      dispatch({type:'REMOVE',id})
    },[])

  const onToggle = useCallback(
    id=>{
      dispatch({type:'TOGGLE',id})
    },[]
  )
  const onInsert = useCallback(
    text=>{
      const todo = {
        id:nextId.current,
        text,
        checked:false
      };
      dispatch({type:'INSERT',todo})
      nextId.current+=1;
    },
    []
  )

useReducer(todoReducer,undefined,createBulkTodos)

두번째 파라미터에 초기상태를 넣어줘야한다. → undefined

세번째 파라미터에 초기상태를 만들어주는 함수를 넣었다 → 맨 처음 렌더링할때만 호출

react-virtualized

$ yarn add react-virtualized 설치

  • 스크롤을 해야 렌더링을 하게 한다
  • 각 항목의 실제 크기를 px 단위로 알아봐야한다.

꼭 최적화를 할 필요는 없지만 보여줘야 할 항목이 몇 백개고 업데이트가 잦다면 권장한다.

profile
FE - devp

0개의 댓글