끄적끄적

[REACT] React Hooks 란? 본문

Front-end/React.js

[REACT] React Hooks 란?

mashko 2021. 3. 15. 23:41
반응형

리액트 훅이란?
리액트를 사용하는 개발자라면 한번쯤은 들어봤을 훅에 대해서 정리해보려고 합니다.
이미 많은 자료가 있지만 한번 정리해두면 나중에 편할 것 같아서..

Hooks 는 리액트 v16.8 에 새로 도입된 기능이며, 함수형 컴포넌트에서도 상태 관리를 할 수 있는 useState, 
그리고 렌더링 직후 작업을 설정하는 useEffect 등의 기능을 제공해,
기존 함수형 컴포넌트에서 할 수 없었던 작업을 할 수 있게 해줍니다.

훅의 종류

1.useState
useState는 가장 기본적인 Hook입니다,
함수형 컴포넌트에서 가변적인 상태를 지닐 수 있게 해주며, 함수형 컴포넌트에서 상태를 관리해야 할 때 사용합니다.

import React, { useState } from 'react';

위의 예제와 같이 불러오고

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

위의 예제와 같이 사용합니다.

const Example = () => {
  const [value, setValue] = useState(0);
  return (
    <div>
      <p>
        {value}
      </p>
      <button onClick={() => setValue(value + 1)}>increment</button>
      <button onClick={() => setValue(value - 1)}>decrement</button>
    </div>
  );
};

위에 같이 함수형 컴포넌트안에서 사용할 수 있습니다.

2.useEffect
useEffect는 클래스형 컴포넌트의 componentDidMount 와 componentDidUpdate 를 합친 형태라고 생각하면 될 것 같습니다.
랜더링 될때마다의 특정 작업을 할 수 있도록 도와줍니다.

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

위와 같이 불러오고

useEffect(() => {
    console.log('useEffect');
});

위와 같이 사용합니다.

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

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

  useEffect(() => {
      console.log('랜더링이 되었습니다.');
  });

  return (
    <div>
      <p>
        {value}
      </p>
      <button onClick={() => setValue(value + 1)}>increment</button>
      <button onClick={() => setValue(value - 1)}>decrement</button>
    </div>
  );
};

위와같은 방법으로 함수형 컴포넌트에서 사용할 수 있습니다.

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

위와 같은 방법으로 컴포넌트가 화면에 가장 처음 렌더링 될 때만 실행 할 수 있습니다.

useEffect(() => {
  console.log('업데이트 될때만 실행');
}, [value]);

위와 같은 방법으로 특정 상태가 변화할때만 실행 될 수 있게 할 수 있습니다.

3.useContext
useContext는 React Context를 조금 더 편하게 사용할 수 있게 해줍니다.

import React, { createContext, useContext } from 'react';

위와 같은 방법으로 불러옵니다.

import React, { createContext } from 'react';

const AppContext = createContext();

const App = () => {
  const sample = {
    key: 'key',
    value: 'value'
  }

  return (
    <AppContext.Provider value={sample}>
        <useComponent />
    </AppContext.Provider>
  )
}

const useComponent = () => (
  <AppContext.Consumer>
    {sample => {
          return (
            <div>
              <div>{sample.key}</div>
              <div>{sample.value}</div>
            </div>
          )
    )}
  </AppContext.Consumer>
)

기존의 위와 같은 코드를 useContext를 이용해봅시다.

import React, { createContext, useContext } from 'react';

const AppContext = createContext();

const App = () => {
  const sample = {
    key: 'key',
    value: 'value'
  }

  return (
    <AppContext.Provider value={sample}>
        <UseComponent />
    </AppContext.Provider>
  )
}

const UseComponent = () => {
    const sample = useContext(AppContext);

     return (
        <div>
          <div>{sample.key}</div>
          <div>{sample.value}</div>
        </div>
     )
}

위와 같이 조금 더 편리하게 쓸 수 있습니다.

4.useReducer
useReducer는 Redux를 써본 사람이라면 조금 더 쉽게 이해 할 수 있을 것 같습니다.
리듀서는 현재 상태와, 업데이트를 위해 필요한 정보를 담은 액션 값을 전달 받아 새로운 상태를 반환하는 함수입니다.
리듀서 함수에서 새로운 상태를 만들 때는 꼭 불변성을 지켜주어야 합니다.

import React, { useReducer } from 'react';

위와 같은 방법으로 불러옵니다.

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

function reducer(state, action) {
  switch (action.type) {
    case 'INCREMENT':
      return { value: state.value + 1 };
    case 'DECREMENT':
      return { value: state.value - 1 };
    default:
      return state;
  }
}

const Example = () => {
  const [state, dispatch] = useReducer(reducer, { value: 0 });

  return (
    <div>
      <p>
        {value}
      </p>
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>increment</button>
      <button onClick={() => dispatch({ type: 'DECREMENT' })}>decrement</button>
    </div>
  );
};

위와 같은 방법으로 사용합니다.
useReducer는 첫번째 리듀서 함수, 두번째는 해당 리듀서의 기본 값을 할당합니다.

5.useMemo
useMemo는 함수형 컴포넌트 내부에서 발생하는 연산을 최적화 할 수 있습니다.

import React, { useMemo } from 'react';

위와 같은 방법으로 불러옵니다.

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

const User = () => {
  const [name, setName] = useState('');
  const [nameLength, setNameLength] = useState(0);

  const updateNameLength = () => {
    setNameLength(name.length)
  };

  useEffect(updateNameLength, [name]);

  const updateName = event => {
    const name = event.target.value;
    setName(name);
  };

  return (
    <div>
      <input onChange={updateName} />
      <label>{nameLength}</label>
    </div>
  )
}

useMemo를 쓰면 구현된 코드를 조금 더 간편하게 구현할 수 있습니다.

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

const User = () => {
  const [name, setName] = useState('');
  const nameLength = useMemo(() => name.length, [name]);

  const updateName = event => {
    const name = event.target.value;

    setName(name);
  }

  return (
    <div>
      <input onChange={updateName} />
      <label>{nameLength}</label>
    </div>
  )
}

위와 같이 useMemo를 쓰면 computed와 같은 효과의 연산시 name의 변화를 감지해 간편하게 연산에 도움을 줍니다.

6.useCallback
useCallback 은 useMemo와 비슷하며, 주로 렌더링 성능을 최적화해야 하는 상황에서 사용합니다.
useCallBack을 사용하면 이벤트 핸들러 함수를 필요할 때만 생성 할 수 있습니다.

import React, { useCallback } from 'react';

위와 같이 불러옵니다.

useCallback(() => {
  console.log('hello world!');
}, []);

위와 같이 사용합니다.

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

const User = () => {
  const [name, setName] = useState('');
  const nameLength = useMemo(() => name.length, [name]);

  const updateName = useCallBack(event => {
    setName(event.target.value);
  }, []); // 컴포넌트가 처음 렌더링 될 때만 함수 생성 []안에 상태를 대입하면 해당 상태가 바뀌었을 때만 함수 생성

  return (
    <div>
      <input onChange={updateName} />
      <label>{nameLength}</label>
    </div>
  )
}

이전에 코드를 위와같이 바꿀 수 있습니다.

7.useRef
useRef는 함수형 컴포넌트에서 ref 를 쉽게 사용 할 수 있게 해줍니다.
어떻게 편리하게 사용되는지 보죠.

import React, { useRef } from 'react';

위와 같이 불러옵니다.

const el = useRef(null);

위와 같이 사용합니다.

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

const User = () => {
  const [name, setName] = useState('');
  const nameLength = useMemo(() => name.length, [name]);
  const inputEl = useRef(null);

  const updateName = useCallBack(event => {
    setName(event.target.value);
  }, []); // 컴포넌트가 처음 렌더링 될 때만 함수 생성 []안에 상태를 대입하면 해당 상태가 바뀌었을 때만 함수 생성

  const onClickHandler = useCallback(
    e => {
        inputEl.current.focus();
    }
  );

  return (
    <div>
      <input onChange={updateName} ref={inputEl} />
      <label>{nameLength}</label>
      <button onClick={onClickHandler}>click</button>
    </div>
  )
}

위와 같이 불필요한 코드를 작성하지 않고 useRef를 사용해 ref를 설정하면, useRef를 통해 만든 객체 안의 current 값이 실제 엘리먼트를 가르키게 됩니다.

반응형
Comments