티스토리 뷰

TIL/React

[리액트 React] 리액트 훅(React Hook)

개춘기뽀삐 2024. 1. 25. 20:22

 Hook 

state와 생명주기 기능에 갈고리를 걸어 원하는 시점에 정해진 함수를 실행 되도록 만든 것

 

Hook 규칙

  • 최상위에서만 호출한다
  • 반복문, 조건문, 중첩 함수 내에서 호출 불가 (호출 순서에 의지하기 때문에 해당 부분을 건너뛰는 일이 생길 수 있다)
  • React 함수 내에서만 호출이 가능하다, 일반적인 js에선 사용 불가 컴포넌트 내부에서만 사용할것

 

Hook의 종류


useState

  • 가장 기본적인 hook
  • 함수형 컴포넌트 내에서 가변적인 상태를 갖게한다
  • 문법 const [state, setState] = useState(초기값);
  • 원래 useState의 리턴값은 배열이다, [state, setState] 이렇게 구조분해할당을 통해 값을 받은 것

배치 업데이트

  • 컴포넌트가 여러 번 업데이트 되더라도, 실제 DOM 요소에 변경사항을 적용하는 것을 최소화하여 애플리케이션의 성능을 최적화하는 기능
  • State() 메서드를 호출하면, 컴포넌트의 상태(State)를 변경하는 것이지만, 실제 변경사항이 적용되는 시점은 render() 함수 호출 후 적용되기때문에 setState() 메서드를 여러번 호출하더라도, 배치로 처리되어 실제 변경사항이 적용되는 시점이 늦춰지게된다

 

기존 setState 업데이트 방법

  • 배치성으로 처리된다, 배치 업데이트. 한꺼번에 변경된 내용을 모아서 한번만 업데이트한다 setNumber에 값을 3번 넣어줬대도 명령을 모아서 한번으로 처리한다
function App() {
  const [number, setNumber] = useState(0);

  return (
    <>
      <div>Number State : {number}</div>
      <button
        onClick={() => {
          setNumber(number + 1)
          setNumber(number + 1)
          setNumber(number + 1)
        }}
      >
        Up
      </button>
    </>

 

함수형 setState 업데이트 방법 

  • setState(함수를 넣고 매개변수로 현재 State를 가져올 수 있다.)
  • 명령들을 모아서 순차적으로 한번씩 실행시킨다. 인자 부분에 현재 스테이트를 받고 바뀐 스테이트를 내보내기때문에 최신값을 유지할수있는것 (함수는 인풋과 아웃풋이 있다, 들어오면 내보내야함)
function App() {
  const [number, setNumber] = useState(0);

  return (
    <>
      <div>Number State : {number}</div>
      <button
        onClick={() => {
          setNumber((currNum) => currNum + 1);
          setNumber((currNum) => currNum + 1);
          setNumber((currNum) => currNum + 1);
        }}
      >
        Up
      </button>
    </>

 


useEffect

  • 렌더링 될 때, 특정한 작업을 수행해야 할 때 설정하는 훅 (ex.alert, console... 등)
  • 컴포넌트가 렌더링 또는 리렌더링 시, 컴포넌트가 사라졌을때(컴포넌트가 죽었을 때) 실행된다
  • [ ] 의존성 배열(dependency array) 배열에 값을 넣으면, 그 값이 바뀔때만 useEffect을 실행한다

 

사용 방법

  • 컴포넌트가 렌더링 될 때마다 console이 실행된다 
  useEffect(() => {
    console.log("hi useEffect");
  }, []);

 

조건부 실행(의존성 배열) 

  • 의존성 배열 - useEffect 함수가 끝나는 부분 뒤에 배열 형태로 넣는것
  • [ ]안에 값이 바뀔때 useEffect를 실행시키기 위한 조건(값)을 넣는것
  • 의존성 배열 넣지 않을 경우, 리렌더링될때마다 useEffect가 실행되었지만, 배열에 값을 넣으면 처음 렌더링 됐을때와 값이 바뀔때만 실행된다(첫 렌더링 시 실행은 무조건임)

 

이해를 돕기 위한 설명

  1. 렌더링하면 useEffect가 먼저 실행된다.
  2. input 에 값을 입력하면 value, 즉 state(상태)가 변경됨
  3. state가 변경되었기 때문에 App 컴포넌트가 리렌더링된다
  4. 리렌더링이 되면 useEffect가 다시 실행된다 input 값이 바뀔때마다 리렌더링 되고, useEffect가 계속 실행됨
  5. useEffect가 실행될때마다 리렌더링이 되고 있는 것
  useEffect(() => {
    console.log(`hi useEffect : ${value}`);
   
  }, [value]);

  return (
    <div>
      <input
        type="text"
        value={value}
        onChange={(e) => setValue(e.target.value)}
      />
    </div>
  );

 

clean Up

  • 컴포넌트가 사라졌을때 실행
  useEffect(() => {
    console.log(`hi useEffect : ${value}`);
    return () => {

      console.log("나 사라진다아");
    };
  }, [value]);

useRef

  • DOM요소에 접근하고, 변수의 저장공간으로 쓰인다
  • state는 변화가 일어나면 다시 렌더링이 일어나 변수들은 초기화 되지만, useRef 저장된 값은 렌더링을 일으키지 않기 때문에 변수들이 초기화되는걸 막을 수 있다
  • state - 리렌더링이 꼭 필요한 값에 사용(변화되는 값)
  • useRef - 렌더링을 발생시키지 않는 값을 저장할때 사용

 

사용 방법

  • 콘솔을 확인헤 보면 객체형태로 되어있다 ref {current(키) : '초기값'(값)}
  • 키에 접근하여 값을 변경하면 변경된 값이 출력된다
  • 설정된 값은 컴포넌트가 계속 렌더링 되어도 unmount되기전까지(컴포넌트가 죽기 전까지) 계속 값을 유지한다
const ref = useRef("초기값");
  console.log("ref", ref);

ref.current = "변경값"; 
  console.log("ref", ref);

 

  • plusStateCnt는 state로 연결되어있어 버튼을 누르면 화면에서 count가 올라간다
  • plusRefCount는 화면 변화는 없지만 콘솔을 확인하면 count가 올라가고 있다
const plusStateCnt = function () {
    return setCount(count + 1);
  };

  const plusRefCount = () => {
    countRef.current++;
    console.log(countRef.current);
    // 버튼을 클릭하면 화면상에 변화는 없지만 콘솔에서는 잘 작동한다
  };
  return (
    <>
      <div style={style}>
        state 영역입니다 {count} <br />
        <button onClick={plusStateCnt}>state 증가</button>
      </div>

      <div style={style}>
        ref 영역입니다 {countRef.current} <br />
        <button onClick={plusRefCount}>ref 증가</button>
      </div>
    </>

 

Focus 적용 방법(useEffect , useRef)

  • 화면이 렌더링 되면, 아이디 포커스
  const idRef = useRef(""); // 아이디 포커스

  const [id, setId] = useState("");

  useEffect(function () {
    return idRef.current.focus(); 
  }, [ ]);

    아이디 :
        <input
          type="text"
          ref={idRef}
          value={id}>

 

 

ID가 10자리를 넘으면 비밀번호에 focus 옮기는 방법

  • id의 값이 바뀔때마다 useEffect가 실행돼야하니까 의존성 배열에 변경 기준 값으로 id를 넣어줌
  useEffect(() => {
    if (id.length >= 10) {
      pwRef.current.focus();
    }
  }, [id]);

      <div>
        아이디 :
        <input
          type="text"
          ref={idRef}
          value={id}
          onChange={(e) => {
            setId(e.target.value);

            // State로 작성할 경우,  useState는 배치업데이트로 setId 값이 변해도 바로 적용되는게 아니기때문에
            // 11자리를 입력해야 포커스가 넘어간다, useEffect를 사용하는게 더 효과적임
            // id(id.length >=10){
            //   pwRef.current.focus();
            // }
          }}
        />
      </div>
      <div>
        비밀번호 <input type="password" ref={pwRef} />
      </div>

 


useContext

  • 전역 데이터 관리, 어떤 컴포넌트든 전역 데이터에 접근할 수 있다
  • useContext 사용 시 Provider에서 제공한 value가 달라진다면(GF) useContext를 사용하고 있는 모든 컴포넌트가 리렌더링되므로 value 부분 신경쓸것

사용 방법

  • 목적 : GF가 Child한테 정보를 전달하여 Child한테 내용을 출력하도록 하자
  1. 하위 컴포넌트가 모두 접근 할 수 있는 전역객체 FamilyContext생성
  2. 정보를 보낼 부모와 컨텍스트 연결, 정보를 내려줄 자식 컴포넌트 연결
  3. 기존에는 props를 이용했지만 Provider value={{ houseName, pocketMoney }} 으로 데이터 전달
  4. 데이터를 받은 Child 컴포넌트는 GF가 FamilyContext에 담아 보낸 정보를 useContext를 통해 변수에 담아 꺼낸다(컨텍스트 이름을 넣어야함)
export const FamilyContext = createContext(null);
// 하위컴포넌트들이 사용할 수 있는 컴포넌트

* 최상위 컴포넌트
function App() {
  return <GrandFather />;
}

  const houseName = "스파르타"; // 집안 이름
  const pocketMoney = 10000; // 손자 용돈

  return (
    // Father 컴포넌트 아래로 FamilyContext를 제공해준다는 의미
    // props를 value로 보낸다(객체니까 {} 안에 담아야함)
 
    <FamilyContext.Provider value={{ houseName, pocketMoney }}>
      <Father />
    </FamilyContext.Provider>
  );
}

function Child() {
  // GF가 FamilyContext에 담아 보낸 정보를 useContext를 통해 변수에 담아 꺼낸다(컨텍스트 이름을 넣어야함)
  const data = useContext(FamilyContext);
  console.log("data", data);

  return (
    <div>
      나는 이 집안의 막내에요 <br />
      할아버지가 우리 집 이름은 <span style={style}>{data.houseName}</span>라고
      하셨어요 <br />
      게다가 용돈도 <span style={style}>{data.pocketMoney}</span>원이나 주셨어요
    </div>
  );
}
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함