본문 바로가기

Frontend/React

2021-04-05 :: Hooks2

8.4 use Memo

useMemo를 사용하면 함수형 컴포넌트 내부에서 발생하는 연산을 최적화 할 수 있다.

 

숫자를 등록할 때뿐만 아니라 인풋 내용이 수정될 때도 우리가 만든 getAverage 함수가 호출되는 것을 확인 할 수 있다. useMemo를 사용하면 렌더링하는 과정에서 특정 값이 바뀌었을 때만 연산을 실행하고, 원하는 값이 바뀌지 않았다면 이전에 연산했던 결과를 다시 사용하는 방식이다.

import React, {useState, useMemo} from 'react';

const getAverage = numbers => {
   console.log('계산중..');
   if(numbers.length === 0) return 0;
   const sum = numbers.reduce((a, b)=> a+b);
   return sum/numbers.length;
}


const Average=()=> {
   const [list, setList] = useState([]);
   const [number, setNumber] = useState('');

   const onChange = e => {
      setNumber(e.target.value);
   }

   const onClick = () => {
      let newList = list.concat(parseInt(number));
      setList(newList);
      setNumber('');
   }

   const onKeyPress = (e) => {
      if(e.key === 'Enter')
         onClick();
   }
   
   const avg = useMemo(()=>getAverage(list), [list]);

   return(
      <>
         <input value={number} onChange={onChange} onKeyPress={onKeyPress}/>
         <button onClick={onClick}>등록</button>
         <ul>
            {list.map((value, index)=>(
               <li key={index}>{value}</li>
            ))}
         </ul>
         <p>평균값: {avg}</p>
      </>
   )
};

export default Average;

Array.prototype.reduce()

developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

 

Array.prototype.reduce() - JavaScript | MDN

Array.prototype.reduce() reduce() 메서드는 배열의 각 요소에 대해 주어진 리듀서(reducer) 함수를 실행하고, 하나의 결과값을 반환합니다. The source for this interactive example is stored in a GitHub repository. If you'd

developer.mozilla.org

8.5 useCallback

useCallback은 useMemo와 상당히 비슷한 함수이다. 주로 렌더링 성능을 최적화해야 하는 상황에서 사용된다. 이 Hook을 사용하면 이번트 핸들러 함수를 필요할 때만 생성할 수 있다. 보통 컴포넌트가 리렌더링 될 때 컴포넌트에 포함된 함수 역시 새로 생된된다. 컴포넌트의 렌더링이 자주 발생하거나 렌더링해야 할 컴포넌트의 개수가 많다면 이 부분을 최적화해 주는 것이 좋다.

 const onChange = useCallback(e=> {
    setNumber(e.target.value);
 }, []) //컴포넌트가 처음 렌더링될 때만 함수 생성

 const onClick = useCallback(() => {
    let newList = list.concat(parseInt(number));
    setList(newList);
    setNumber('');
 }, [number, list]); //number 혹은 ㅣist가 바뀌었을 때만 함수 생성

 const onKeyPress = (e) => { //ㅇ
    if(e.key === 'Enter')
       onClick();
 }//얘는 useCallback 쓰면 warnig 뜸, onClick이랑 연관있어 보임

useCallback의 첫 번째 파라미터에는 생성하고 싶은 함수를 넣고, 두 번째 파라미터에는 배열을 넣으면 된다.  이 배열에는 어떤 값이 바뀌었을 때 함수를 새로 생성할 것인지 명시해야 한다.

onChange처럼 비어 있는 배열을 넣게 되면 컴포넌트가 렌더링될 때 단 한 번만 함수가 생성되며, onClick처럼 배열 안에 number와 list를 넣게 되면 인풋 내용이 바뀌거나 새로운 항목이 추가될 때마다 함수가 생성된다.

함수 내부에서 상태 값에 의존해야 할 때는 그 값을 반드시 두 번째 파라미터 안에 포함시켜 주어야 한다. 예를 들어 onClick의 newList는 기존의 number와 list를 조회하여 생성하기 때문에 배열 안에 number와 list를 꼭 넣어 주어야 한다.

 

결국 useCallback은 useMemo로 함수를 반환하는 상황에서 더 편하게 사용할 수 있는 Hook이다.

8.6 커스텀 Hooks 만들기

여러 컴포넌트에서 비슷한 기능을 공유할 경우, 자신만의 Hook으로 작성하여 로직을 재사용할 수 있다.

기존 Info 컴포넌트에서 여러 개의 인풋을 관리하기 위해 useReducer로 작성했던 로직을 useInputs라는 Hook으로 따로 분리해 보겠다.

import {useReducer} from 'react';

function reducer(state, action) {
   return(
      ...state,
      [action.name]: action.value;
   );
}

export default function useInputs(initialForm) {
   const [state, dispatch] = useReducer(reducer, initialForm);
   const onChange = e => {
      dispatch(e.target);
   };
   return [state, onChange];
}
   const [state, onChange] = useInputs({
      name: '',
      nickname: ''
   });

 

8.7 정리

리액트에서 Hooks 패턴을 사용하면 클래스형 컴포넌트를 사용하지 않고도 대부분의 기능을 구현할 수 있다.

메뉴얼에서는 새로 작성하는 컴포넌트의 경우 함수형 컴포넌트와 Hooks를 사용할 것을 권장하고 있다.

'Frontend > React' 카테고리의 다른 글

2021-04-23 :: 리액트 라우터로 SPA 개발하기  (0) 2021.04.27
2020-04-08 :: ref: DOM에 이름 달기  (0) 2021.04.08
2021-04-05 :: Hooks1  (0) 2021.04.05
2020-12-07 :: Event Handling  (0) 2020.12.08
2020-12-03 :: State  (0) 2020.12.04