IT/React

리액트(React) 스터디일지9: Hooks

라임웨일 2021. 4. 8. 16:32
반응형

 

이전 컴포넌트에서 잠깐 다룬 적이 있는 함수형 컴포넌트의 새로운 기능 Hooks를 알아보려고 합니다. Hooks는 리액트 v16.8에 새로 도입된 기능으로 함수형 컴포넌트에서도 상태 관리를 할 수 있는 useState, 랜더링 직후 작업을 설정하는 useEffect 등의 기능을 제공하여 기존의 함수형 컴포넌트에서 할 수 없었던 다양한 작업을 할 수 있게 도와줍니다.

 

1.useState

useState를 사용하기 위해서는 React에 useState를 선언해 주어야 합니다.

import React, { useState } from 'react';

 

useState 함수는 파라미터에 상태의 기본값을 넣어줍니다.  이 함수는 배열을 반환하며 첫 번째 원소는 상태 값, 두 번째 원소는 상태를 설정하는 함수를 나타냅니다. 

 

하나의 useState 함수는 하나의 상태 값만을 관리하게 됩니다.

const [value, setValue] = useState(0);

 

2.useEffect

리액트 컴포넌트가 랜더링 될 때마다 특정 작업을 수행하도록 설정할 수 있는 hooks입니다.

useEffect(() => {
    console.log('랜더링 완료');
    console.log({ name, nickName });
});

 

useEffect는 마운트가 될 때만 실행을 할 수도 있습니다.

useEffect(() => {
    console.log('마운트 될 때만 실행');
    console.log({ name, nickName });
}, []);

useEffec에서 설정한 함수를 컴포넌트가 화면에 맨 처음 랜더링 될 때만 실행하고 업데이트될 때는 실행하지 않으려면 함수의 두 번째 파라미터로 비어 있는 배열을 넣어주면 됩니다.

 

기존 클래스형과 한번 비교를 해보겠습니다.

클래스 형

ComponentDidUpdate(prevProps, prevState) {
  if(prevProps.value !== this.props.value) {
    // 이벤트 발생
  }
}

함수형

비교를 통해서 보니 훨씬 코드가 간결해지죠. 두 번째 배열 안에 검사하고 싶은 갑을 넣어줍니다. 배열 안에는 useState를 통해 관리하는 상태를 넣어주어도 되고 props로 전달받은 값을 넣어줘도 괜찮습니다. 일반적으로랜더링 되고 난 직후마다 실행되며 두 번째 파라미터 배열에 무엇을 넣는가에 따리 실행되는 조건이 달라지게 됩니다.

useEffect(() => {
    console.log('마운트 될 때만 실행');    
}, [name, nickName]);

 

3.useReducer

리듀서 함수에서 새로운 상태를 만들 때는 반드시 불변성을 지켜야 합니다. useReducer의 첫 번째 파라미터에는 리듀서 함수를 넣고, 두 번째 파라미터에는 해당 리듀서의 기본값을 넣어줍니다.

 

이 hook을 사용하며 state와 dispatch 함수를 받아오게 됩니다.

state는 현재 가리키고 있는 상태, dispatch는 액션을 발생시키는 함수를 가리킵니다.

dispatch(action)과 같은 형태로 함수 파라미터로 액션 값을 넣어주면 리듀서 함수가 호출되는 구조입니다.

 

import React, { useReducer } from 'react';

const Counter = () => {
  function reducer(state, action) {
    switch (action.type) {
      case 'INCREMENT':
        return { value: state.value + 1 };
      case 'DECREMET':
        return { value: state.value - 1 };
      default:
        // 아무것도 해당되지 않을 때 기존 상태 반환
        return state;
    }
  }
  const [state, dispatch] = useReducer(reducer, { value: 0 });
  return (
    <div>
      <p>
        현재 카운터 값은 <b>{state.value}</b>입니다.
      </p>
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>+1</button>
      <button onClick={() => dispatch({ type: 'DECREMET' })}>-1</button>
    </div>
  );
};

export default Counter;

useReducer를 사용했을 때 가장 큰 장점은 컴포넌트 업데이트 로직을 컴포넌트 바깥으로 빼낼 수 있다는 점입니다.

import React, { useReducer } from 'react';

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

const Info = () => {
  const [state, dispatch] = useReducer(reducer, {
    name: '',
    nickname: '',
  });

  const { name, nickname } = state;
  const onChange = (e) => {
    dispatch(e.target);
  };

  return (
    <div>
      <div>
        <input
          name="name"
          value={name}
          onChange={onChange}
          placeholder="이름입력"
        />
        <input
          name="nickname"
          value={nickname}
          onChange={onChange}
          placeholder="닉네임 입력"
        />
      </div>

      <div>
        <p>
          <b>이름</b> : {name}
        </p>
        <p>
          <b>닉네임</b> : {nickname}
        </p>
      </div>
    </div>
  );
};

export default Info;

 

4.useMemo

useMemo를 사용하면 함수형 컴포넌트에서 발생하는 연산을 최적화할 수 있습니다. 랜더링 되는 과정에서 특정값이 바뀌었을 때만 실행하고, 원하는 값이 바뀌지 않았다면 랜더링이 되지 않게 처리됩니다.

 

5.useCallback

useMemo와 상당히 비슷한 함수로 랜더링 성능이 최적화되어야 하는 상황에서 사용하게 됩니다.

첫 번째 파라미터에는 생성하고 싶은 함수를 넣고, 두 번째 파라미터에는 배열을 넣으면 됩니다.. 이 배열에는 어떤 값이 바뀌었을 때 함수를 새로 생성해야 하는지 명시해 주어야 합니다.

비어있는 배열을 넣으면 컴포넌트가 랜더링 될 때 만들었던 함수가 계속해서 재사용하게 됩니다.

const onInsert = useCallback(()=> {
    이벤트 발생
},[number, list]); // mumber, 혹은 list가 바뀌었을 때만 함수 생성.

 

반응형