useCallback, 커스텀 훅(useInput) 사용 정리

개발공부·2022년 11월 9일
0

React 공부하기

목록 보기
5/14

* (문제점) Input에 value값과 onChange 부분이 계속해서 중복 발생

▶ 매번 만드는 것보다 한 번에 정리하는 것이 낫지 않나?
▶ 해결책 : 커스텀 훅
▶ useCallback에 대해 확실히 알고 있나? -> 정리 필요

* useCallback

(참고 : https://www.daleseo.com/react-hooks-use-callback/)
▶ 첫 번째 인자 : 함수
▶ 두 번째 인자 : 배열 내의 값이 변경될 때까지 저장하고 재사용할 수 있게 함
두 번째 인자로 넘어온 의존 배열이 변경될 때만 첫 번째 넘어온 함수 호출함

const showUseCallback = useCallback(함수, 배열)

* useCallback() 사용이 도움되는 경우

▶ 컴포넌트가 다시 렌더링되더라도 예시 함수(여기서는 fetchUser 함수) 참조값 동일하게 유지, useEffect()로 넘어온 함수는 userId값이 변경되지 않는 한 재호출 되지 않음

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

function Profile({ userId }) {
  const [user, setUser] = useState(null);

// 수정 전 : userId가 바뀌든 말든 컴포넌트가 렌더링 될 때마다 새로운 참조값 변경됨, 
// useEffect 함수 호출 -> user 상태값 바뀜 
// -> 다시 렌더링 -> 다시 useEffect 함수 호출
  
  const fetchUser = () =>
    fetch(`https://your-api.com/users/${userId}`)
      .then((response) => response.json())
      .then(({ user }) => user);
      
// 수정 후 : fetchUser 함수의 참조값 동일하게 유지
// userId값이 변경되지 않는 한 재호출 되지 않음

  const fetchUser = useCallback(
    () =>
      fetch(`https://your-api.com/users/${userId}`)
        .then((response) => response.json())
        .then(({ user }) => user),
    [userId]
  );
     
  useEffect(() => {
    fetchUser().then((user) => setUser(user));
  }, [fetchUser]);

  // ...
}

[예시 - 회원가입]

import React, { useCallback, useState } from "react";

const JoinForm = () => {
  const dispatch = useDispatch();
  
  const [email, setEmail] = useState("");
  const [nickname, setNickname] = useState("");
  const [password, setPassword] = useState("");
  
  const onChangeEmail = useCallback((e) => {
  	setEmail(e.target.value)
  })
  
  const onChangeNickname = useCallback((e) => {
  	setNickname(e.target.value)
  })
  
  const onChangePassword = useCallback((e) => {
  	setPassword(e.target.value)
  })


  const onSubmitUserForm = useCallback(() => {
    console.log(email, password, nickname);
    dispatch(
      signupRequest({
        email,
        password,
        nickname,
      })
    );
  }, [password, passwordCheck, term]);
  
  return (
    <div>
      <div>
        <div>
          <div>

          </div>
          <h4>
            회원가입
          </h4>
        </div>
        <form
          className="mt-8 space-y-6"
          action="#"
          method="POST"
          onSubmit={onSubmitUserForm}
        >
          <input type="hidden" name="remember" defaultValue="true" />
          <div className=" rounded-lg shadow-sm">
            <div>
              <label htmlFor="email-address" className="sr-only">
                Email address
              </label>
              <input
                id="email-address"
                value={email}
                name="email"
                type="email"
                autoComplete="email"
                required
                placeholder="Email"
                onChange={onChangeEmail}
              />
            </div>
            <div>
              <label htmlFor="nickname" className="sr-only">
                nickname
              </label>
              <input
                id="nickname"
                value={nickname}
                name="nickname"
                type="text"
                autoComplete="current-nickname"
                required
                placeholder="Nickname"
                onChange={onChangeNickname}
              />
            </div>
            <div>
              <label htmlFor="password" className="sr-only">
                Password
              </label>
              <input
                id="password"
                value={password}
                name="password"
                type="password"
                autoComplete="current-password"
                required
                placeholder="Password"
                onChange={onChangePassword}
              />
            </div>
          <div>
            <button
             type="submit">
              Sign up
            </button>
          </div>
        </form>
      </div>
    </div>
  );
};

export default JoinForm;

[중복되는 것]
▶ 로그인이나 input이 필요한 경우들도 중복됨(내 프로젝트에서는 단어 생성, 수정에서도 같이 적용됨)

const [email, setEmail] = useState("");
const onChangeEmail = useCallback((e) => {
setEmail(e.target.value)
})

* 커스텀 훅(useInput.js)

import { useState, useCallback } from "react";

export default (initValue = null) => {
  const [value, setValue] = useState(initValue); //initValue = 초기값
  const handler = useCallback((e) => { //onChang~
    setValue(e.target.value);
  }, []);
  return [value, handler]; //useState와 hanlder를 합침
};

* 커스텀 훅 적용한 회원가입

[예시 - 회원가입(커스텀 훅 적용)]

import React, { useCallback, useState } from "react";
import useInput from "../hooks/useInput"; //커스텀 훅 불러옴

const JoinForm = () => {
  const dispatch = useDispatch();
  
  const [email, onChangeEmail] = useInput("");
  const [nickname, onChangeNickname] = useInput("");
  const [password, onChangePassword] = useInput("");

  const onSubmitUserForm = useCallback(() => {
    console.log(email, password, nickname);
    dispatch(
      signupRequest({
        email,
        password,
        nickname,
      })
    );
  }, [password, passwordCheck, term]);
  
  return (
    <div>
      <div>
        <div>
          <div>

          </div>
          <h4>
            회원가입
          </h4>
        </div>
        <form
          className="mt-8 space-y-6"
          action="#"
          method="POST"
          onSubmit={onSubmitUserForm}
        >
          <input type="hidden" name="remember" defaultValue="true" />
          <div className=" rounded-lg shadow-sm">
            <div>
              <label htmlFor="email-address" className="sr-only">
                Email address
              </label>
              <input
                id="email-address"
                value={email}
                name="email"
                type="email"
                autoComplete="email"
                required
                placeholder="Email"
                onChange={onChangeEmail}
              />
            </div>
            <div>
              <label htmlFor="nickname" className="sr-only">
                nickname
              </label>
              <input
                id="nickname"
                value={nickname}
                name="nickname"
                type="text"
                autoComplete="current-nickname"
                required
                placeholder="Nickname"
                onChange={onChangeNickname}
              />
            </div>
            <div>
              <label htmlFor="password" className="sr-only">
                Password
              </label>
              <input
                id="password"
                value={password}
                name="password"
                type="password"
                autoComplete="current-password"
                required
                placeholder="Password"
                onChange={onChangePassword}
              />
            </div>
          <div>
            <button
             type="submit">
              Sign up
            </button>
          </div>
        </form>
      </div>
    </div>
  );
};

export default JoinForm;
profile
개발 블로그, 티스토리(https://ba-gotocode131.tistory.com/)로 갈아탐

0개의 댓글