TIL30. useCallback

김정현·2020년 11월 15일
0

useCallback hooks

<Input name='user-id' value={id} required onChange={onChangeId} />

컴포넌트에서 props로 넘겨주는 함수(위의 예제에서 onChangeId)는 useCallback이 필수적이다.

자식 컴포넌트로 넘겨주는 함수는 무조건 useCallback으로 감싸준다.

문법

useCallback(fn, deps)

함수(fn) 내부에서 쓰는 state를 deps 배열로 넣는다.

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

배열 내에 여러 개의 값이 있다면 그중의 단 하나만 다를지라도 리액트는 effect를 재실행합니다.

이것이 의미하는 바는 다음과 같습니다. [count]를 useEffect, useCallback 등의 두 번째 인수로 넣었다고 가정해 봅시다.

만약 count가 5이고 컴포넌트가 리렌더링된 이후에도 여전히 count는 변함없이 5라면 리액트는 이전 렌더링 시의 값 [5]를 그다음 렌더링 때의 [5]와 비교합니다. 배열 내의 모든 값이 같기 때문에(5 === 5) 리액트는 effect를 건너뛰게 됩니다.

count가 6으로 업데이트된 뒤에 렌더링하면 리액트는 이전에 렌더링된 값 [5]를 그다음 렌더링 시의 [6]와 비교합니다. 이때 5 !== 6 이기 때문에 리액트는 effect를 재실행합니다. 이를 활용하면 최적화가 가능합니다.

또한 특정 state가 특정한 condition 일 때만 callback(또는 effect)를 재실행하고 싶다면 deps 배열의 state에 특정 조건을 넣는 것도 가능합니다.

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count === 5]); // count가 5일 때만 effect를 재실행합니다.

예시1

const onChangePasswordChk = useCallback(
    e => {
      setPasswordError(e.target.value !== password);
      setPasswordCheck(e.target.value);
    },
    [password],
  );

예시2

const LoginForm = () => {
  const [id, , onChangeId] = useInput('');
  const [password, , onChangePassword] = useInput('');
  const onSubmitForm = useCallback(() => {
    // 자식 컴포넌트(LoginForm 컴포넌트에서는 Form, Input 등이 자식컴포넌트)
    // 넘겨주는 함수는 무조건 useCallback으로 감싸준다.
    console.log({
      id,
      password,
    });
  }, [id, password]);

  return (
    <Form onFinish={onSubmitForm}>
      <div>
        <label htmlFor='user-id'>아이디</label>
        <br />
        <Input name='user-id' value={id} onChange={onChangeId} required />
      </div>
      <div>
        <label htmlFor='user-password'>비밀번호</label>
        <br />
        <Input.Password
          name='user-password'
          value={password}
          onChange={onChangePassword}
          required
        />
      </div>
      <div>
        <Button type='primary' htmlType='submit' loading={false}>
          로그인
        </Button>
        <Link href='/signup'>
          <a>회원가입</a>
        </Link>
      </div>
    </Form>
  );
};

export default LoginForm;

0개의 댓글