[번역] 꼭 써봐야 하는 10가지 리액트 커뮤니티의 훅(hook)들

eunbinn·2022년 3월 2일
89

FrontEnd 번역

목록 보기
2/31
post-thumbnail

원문: https://www.dawsoncodes.com/posts/3/10-react-community-hooks-you-should-be-using

프런트엔드 개발에서 리액트는 최고의 도구라고 말 할 수 있습니다. 리액트 그 자체로도 매우 강력하지만, 리액트 커뮤니티에서 만들어진 훅(이하 '커뮤니티 훅')을 사용하면 코드가 훨씬 명확하고 간결해질 뿐만 아니라, 불필요한 리렌더링 및 성능 문제를 방지할 수 있습니다.

우리는 항상 클린 코드를 위해 노력해야 합니다. 제 기준에서 클린 코드에 가까워지며 성능이 뛰어난 코드를 작성하는데 도움이 되는 10가지 커뮤니티 훅을 뽑아봤습니다.

1. React hook form

리액트만으로 폼을 만들려면 입력값의 검증과 그에 수반되는 코드가 지저분해질 수 있다는 문제는 물론이고, 각 입력에 대한 상태를 생성하고 업데이트하는 일이 매우 까다로울 수 있습니다.

React hook form을 사용하면 간단한 코드 몇 줄만으로 모든 무거운 작업을 처리할 수 있습니다. 훨씬 더 간결한 코드로 데이터를 검증하고 에러를 처리할 수 있으며 해당 에러를 사용자에게 표시하는 것 또한 손쉽게 가능합니다.

React hook form은 여기서 언급하는 것보다 훨씬 더 많은 기능을 갖고있습니다. 더 다양한 기능에 대해 알고 싶으시다면, 여기를 참고해주세요.

간단한 사용 예시:

import { useForm } from "react-hook-form";

export default function App() {
  const {
    register,
    handleSubmit,
    watch,
    formState: { errors },
  } = useForm();

  const onSubmit = (data) => console.log(data);

  console.log(watch("example")); // 변수명을 전달하여 입력 값을 확인합니다

  return (
    /* "handleSubmit" 은 "onSubmit" 실행 전에 입력값을 검증합니다 */
    <form onSubmit={handleSubmit(onSubmit)}>
      {/* "register" 함수를 실행하여 훅에 입력값을 대입합니다  */}
      <input defaultValue="test" {...register("example")} />
      {/* 필수 또는 표준 HTML 유효성 검사 규칙을 통한 검증을 포함합니다 */}
      <input {...register("exampleRequired", { required: true })} />
      {/* 만약 입력값 검증을 실패할 경우 에러가 반환됩니다 */}
      {errors.exampleRequired && <span>This field is required</span>}
      <input type="submit" />
    </form>
  );
}

2. useUpdateEffect

리액트 애플리케이션에서 특정 상태가 업데이트될 때만 함수를 호출하려는 경우가 있는데, 이는 업데이트 시에만 동작하는 useEffect라고 볼 수 있습니다.

다른 서드파티 훅을 사용하지 않고도 코드를 작성할 수 있지만, 코드가 지저분해질 수 있다는 문제가 있습니다.

다음은 라이브러리 없이 사용하는 방법입니다.

const mounted = useRef(false);

useEffect(() => {
  if (mounted.current) {
    // 이 함수는 첫 렌더링에 실행되지 않습니다
  } else {
    mounted.current = true;
  }
}, []); // 이 함수는 의존성 리스트가 업데이트 될 때마다 실행됩니다

다음은 훌륭한 훅을 많이 제공하고 있는 react-use 라이브러리를 사용해서 더 깔끔하게 사용하는 방법입니다.

import { useUpdateEffect } from "react-use"

const Home = () => {
  useUpdateEffect(() => {
    // 이 함수는 첫 렌더링에 실행되지 않습니다
    console.log("Runs only if the state updates")
  }, [fName])

  return ( ...)
}

3. useCopyToClipboard

이 훅은 간단합니다. 상태와, 상태를 업데이트하고 클립보드에 복사하는 함수를 반환합니다.

상태는 사용자가 클립보드에 복사하는 문자열 값을 가집니다(사용자의 클립보드에 이미 저장된 텍스트는 읽을 수 없으며 사용자가 웹 사이트에서 복사한 텍스트 값만 가져올 수 있습니다). 함수가 실행될 때 에러가 발생할 경우에는 이 상태 값에 에러 프로퍼티가 추가됩니다.

아래와 같이 간단하게 적용할 수 있습니다.

import { useCopyToClipboard } from "react-use";

const App = () => {
  const [text, setText] = useState("");
  const [state, copyToClipboard] = useCopyToClipboard();

  return (
    <div>
      <input value={text} onChange={(e) => setText(e.target.value)} />
      <button type="button" onClick={() => copyToClipboard(text)}>
        copy text
      </button>
    </div>
  );
};

4. useLocalStorage

브라우저 로컬 스토리지의 사용은 때때로 답답할 수 있습니다. 컴포넌트가 마운트될 때만 로컬 스토리지에 접근할 수 있기 때문에 useEffect 훅 내부에서만 로컬 스토리지를 사용해야 하고, 이에 따라 코드는 더욱 복잡해집니다. 이것이 바로 이 훅이 필요한 이유입니다.

useLocalStorage 훅은 2가지 인자를 가집니다. 첫 번째는 로컬 스토리지에 저장하고 싶은 아이템의 key 값이고, 두 번째는 해당 아이템의 초기값입니다. 만약 해당 아이템이 사용자의 로컬 스토리지에 저장되어있지 않을 경우 초기값을 사용하게 됩니다.

이 훅은 3가지 값을 갖는 배열을 반환합니다. 첫 번째는 아이템의 값이고, 두 번째는 아이템의 값을 업데이트 할 수 있는 function, 마지막은 로컬 스토리지에서 해당 아이템을 제거할 수 있는 함수입니다.

사용 예시:

import { useLocalStorage } from "react-use";

export default function App() {
  const [token, setToken, removeToken] = useLocalStorage("token", "foo"); // 초기값은 foo 입니다

  return (
    <div>
      <div>Value: {token}</div>

      <button onClick={() => setToken("bar")}>bar</button>

      <button onClick={() => setToken("baz")}>baz</button>

      <button onClick={() => removeToken()}>Remove</button>
    </div>
  );
}

5. useHover

이 훅은 특정 엘리먼트가 hover 됐는지 확인할 때 사용됩니다. 이 훅은 다른 훅과는 조금 다른 형태를 가집니다.

JSX 엘리먼트를 useHover에 넘기면 2가지 값을 갖는 배열을 반환합니다. 첫 번째 요소는 JSX 안에 사용할 엘리먼트이고, 두 번째 요소인 isHovered는 엘리먼트가 hover 됐는지 여부를 담고 있는 불리언 상태값입니다.

다음과 같이 적용합니다.

import { useHover } from "react-use";

const App = () => {
  // 여기에서 함수의 hovered 인자를 사용할 수 있습니다
  const element = (hovered: boolean) => (
    <p>Sample text which is {hovered ? "hovered" : "not hovered"}</p>
  );
  // 혹은 훅으로부터 hovered 상태값을 얻을 수 있습니다
  const [textElement, isHovered] = useHover(element);

  return <div>{textElement}</div>;
};

6. useIdle

이 훅은 사용자가 유휴(idle) 상태가 되었는지 아니면 사용자가 활성 상태인지를 확인할 때 사용됩니다. 두 가지 인자를 넘기는데, 첫 번째는 사용자가 유휴 상태가 되었는지 확인할 시간(밀리초)이고 두 번째는 초기값으로, true 또는 false 값을 줄 수 있습니다. 초기값을 설정하지 않을 경우, 디폴트 값인 false로 설정됩니다.

import { useIdle } from "react-use";

const App = () => {
  const isIdle = useIdle(3000); // 만약 사용자가 3초 이상 유휴상태가 되면 true를 반환합니다

  return <div>{isIdle ? "User is idle" : "User is not idle"}</div>;
};

7. useClickAway

이 훅은 특정 UI 컴포넌트의 외부를 클릭할 때마다 함수를 트리거하고자 할 때 유용합니다. 예를 들어 열려 있는 모달 외부를 클릭할 때 모달이 닫히기를 원하는 경우가 있습니다. 이는 즉 사용자가 모달이 아닌 곳을 클릭할 경우, 모달을 닫는 함수를 실행하고자 하는 것입니다.

import { useClickAway } from "react-use";

const App = () => {
  const ref = useRef(null);

  useClickAway(ref, () => {
    console.log("OUTSIDE CLICKED");
  });

  return (
    <div
      ref={ref}
      style={{
        width: 200,
        height: 200,
        background: "red",
      }}
    />
  );
};

8. useDebounce

이 훅은 API로 쿼리를 검색하고 싶지만, 사용자가 단어를 입력할 때마다 요청을 보내고 싶지는 않은 경우에 제일 많이 사용됩니다. (사용자가 단어를 입력할 때마다 요청을 보낸다면 너무 많은 불필요한 API 요청이 가게 되고 서버에 부하가 생길 수 있기 때문입니다.)

이 훅을 활용하면, 사용자가 입력을 마칠 때까지 기다린 후 요청을 보냅니다.

import { useDebounce } from "react-use";

const App = () => {
  const [input, setInput] = useState("");
  const [loading, setLoading] = useState(false);

  useDebounce(
    () => {
      setLoading(true);
      // 여기에서 api 요청을 합니다
      // ...
      // ...
      setLoading(false);
    },
    500,
    // 함수를 실행하기 전 기다릴 시간(밀리초)입니다
    [input] // 변화를 감지할 의존성값입니다
  );

  return <input value={input} onChange={(e) => setInput(e.target.value)} />;
};

9. useWindowSize

이 훅은 스크린의 높이, 너비 값을 반환하고 스크린 사이즈가 변할 때 자동으로 그 값을 업데이트합니다.

import { useWindowSize } from "react-use";

const App = () => {
  // window의 높이와 너비값을 가져옵니다
  const { width, height } = useWindowSize();

  return (
    <div>
      <div>width: {width}</div>

      <div>height: {height}</div>
    </div>
  );
};

10. useSwr

이 훅은 컴포넌트가 마운트될 때 발생하는 요청을 쉽게 처리할 수 있게 해줍니다.

두 가지 인자를 받는데, 첫 번째는 요청의 url이고 두 번째는 서버에 요청을 보내는 fetcher function 입니다.

훅의 반환값은 isValidating, error, 응답 데이터로, isValidating 상태값은 일반적인 로딩 상태값과 동일하게 동작합니다.

mutate() 라는 함수도 반환하는데, API를 다시 페치하는 데에 사용할 수 있습니다. 이 기능은 할 일 목록에서 할 일을 삭제하는 등 일부 데이터를 변조할 때 유용합니다. 작업이 성공한 후 mutate() 함수를 다시 호출하여 최신 데이터를 가져올 수 있습니다.

다음은 컴포넌트가 마운트 될 때 데이터를 페치하는 간단한 예시입니다.

import useSWR from "swr";

const fetcher = (url: string) => fetch(url).then((r) => r.json());

const App = () => {
  const { data, mutate, error, isValidating } = useSWR(
    "https://jsonplaceholder.typicode.com/todos/1",
    fetcher
  );

  if (error) return <div>failed to load</div>;
  if (!data) return <div>loading...</div>;
  return <div>Todo title: {data.title}!</div>;
};

이것이 제가 꼽은 꼭 써봐야 하는 10가지 훅이었습니다. 이 글이 유용했길 바라며, 만약 그렇다면 공유해주시면 감사하겠습니다.

이 글을 읽어주셔서 감사합니다, 혹시 궁금하신 점이나 댓글이 있으시면 언제든지 트위터에 연락해주시고, 매일 글을 올리고 있으니 팔로우 부탁드립니다.

Website: https://dawsoncodes.com

4개의 댓글

comment-user-thumbnail
2022년 3월 6일

이거 정말 필요했어요!!! 감사합니다!

답글 달기
comment-user-thumbnail
2022년 3월 7일

좋은 글 번역해주셔서 감사합니다 :)

답글 달기
comment-user-thumbnail
2022년 4월 22일

좋네요 👍👍

답글 달기
comment-user-thumbnail
2023년 7월 28일

As I wander through the labyrinth of knowledge, your article stands as a guiding light, illuminating the path before me with https://pokemoninfinitefusion.io its brilliance. With every turn of phrase, you have bestowed upon me the wisdom of a thousand sages, and for that, I humbly offer my heartfelt thanks.

답글 달기