개발 공부 기록하기/07. react.js & vue.js

리액트 훅(React Hook) 정리

lannstark 2020. 10. 19. 21:52

와 내가 react 배울때만 해도 hook이라는게 하나도 없었는데 (생각해보면 거의 2.5~3년 전이긴 하네...) 이제는 자료를 찾아봐도 hook 사용이 default가 된 것 같다... 사이드 프로젝트를 해볼까 하여 훅을 간단히 정리해 보았다.

훅 정리

리액트 버전 16.8에 추가되었으며, 함수형 컴포넌트에도 클래스형 컴포넌트의 기능을 사용할 수 있게 하는 기능이다. 새로 시작하는 프로젝트라면 클래스형 컴포넌트는 지양하고 훅을 사용하는 것이 좋다.

useState : state 관리

function App() {
  // useState(초기값)으로 [state이름, setter]를 가져온다
  // state에 객체가 들어갈 수도 있음
  const [number, setNumber] = useState(0)
  const onIncrease = () => {
    setNumber(number + 1);
  }

  return (
    <div className="App">
      <h1>{number}</h1>
      <button onClick={onIncrease}>+1</button>
    </div>
  );
}

useRef : 특정 DOM 선택, 컴포넌트 안의 변수 관리

function App() {
  const header = useRef("Header");
  const onClickButton = () => {
    console.dir(header.current)
  }
  return (
    <div className="App">
      <h1 ref={header}>안녕?</h1>
      <button onClick={onClickButton}>클릭</button>
    </div>
  );
}

useEffect : 생명주기함수 이용

useEffect(function); // 렌더링 결과가 실제 돔에 반영된 후마다 호출
useEffect(function, []); // 컴포넌트가 처음 나타날때 한 번 호출
useEffect(function, [userId]); // userId에 변경되는 경우에만 호출

useEffect의 첫 번째 파라미터 function에서 또 다른 function을 return 할 수 있는데, return된 함수는 컴포넌트가 언마운트 되거나 첫 번째 매개변수로 입력된 함수가 호출되기 직전에 호출된다.

useMemo : 연산한 값 재사용하기

function App() {
  const [nickname, setNickname] = useState('');
  const nicknameLength = useMemo(() => nickname.length, [nickname])
  const updateNickname = e => {
    setNickname(e.target.value);
  }

  return (
    <div className="App">
      <input onChange={updateNickname}/>
      <label>{nicknameLength}</label>
    </div>
  );
}

useEffect랑 뭔가 비슷한 느낌인데.. (위 예시를 useEffect를 사용하거나 const value = 을 이용하여 똑같이 할 수 있음) useMemo를 쓰면 훨씬 효율적이라고 한다.

useCallback : useMemo랑 비슷한데 함수용 ㅋㅋ

function Profile() {
  const [name, setName] = useState('');
  const [age, setAge] = useState(0);

  // onSave가 Profile 렌더링 될 때마다 계속 호출된다. 여기에 useCallback을 사용할 수 있다.
  return (
    <div>
      <UserEdit
        onSave={() => saveToServer(name, age)}
        setName={setName}
        setAge={setAge}
      />
    </div>
  );
}

// useCallback 적용
function Profile() {
  const onSave = useCallback(() => saveToServer(name, age), [name, age]);
}

By veloper wiki(?)

useReducer

useReducer를 사용하면 컴포넌트의 상태 업데이트 로직을 컴포넌트에서 분리시킬 수 있다. 컴포넌트 바깥에 로직을 작성할 수도 있고, 심지어 다른 파일에 작성 후 불러와서 사용할 수도 있다.

reducer란 현재 상태와 액션 객체를 파라미터로 받아와서 새로운 상태를 반환해주는 함수이다.

function reducer(state, action) {
  // 로직 처리
  return nextState;
}

예시

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

// Component (위의 로직과 분리되었다)
function Counter() {
  const [number, dispatch] = useReducer(reducer, 0);
  const onIncrease = () => dispatch({type: 'INCREMENT'});
  const onDecrease = () => dispatch({type: 'DECREMENT'});

  return (
    // ...
  )
}

useContext

Context API를 통해 만들어진 Context에서 제공하는 value를 가져올 수 있다.

// App -> Users -> User 순서로 Component가 흘러가고
// App에 있는 유저 배열을 지우는 함수를 User로 주기위해
// Users는 단순 전달 역햘만 하고 있었다 해보자

/* App.js */
export const UserDispatch = React.createContext(null);

// dispatch는 useReducer로 정의된 dispatch이다 정의된 
return (
  <UserDispatch.Provider value={dispatch}>
    <Users
      users={users}
    />
  </UserDispatch.Provider>
);

이 외에도

  • 부모 컴포넌트에서 접근 가능한 함수를 구현하게 해주는 useImperativeHandle
  • useEffect와 거의 비슷하지만 동기로 호출되는 useLayoutEffect
  • 리액트 개발자 도구에서 상태 확인을 쉽게 해주는 useDebugValue

등이 존재한다.

/* useDebugValue 예시 */
function useToggle(initialValue) {
  const [value, setValue] = useState(initialValue);
  const onToggle = () => setValue(!value);
  useDebugValue(value ? 'on' : 'off');
  return [value, onToggle];
}