[TIL - 리액트 Hook]

..·2023년 4월 18일
0

TIL

목록 보기
11/22
post-thumbnail

React Hooks (1)

useState

가장 기본적인 hook

함수형 컴포넌트 내에서 가변적인 상태를 갖게 함

카운터, Todolist

const[state,setState] = useState(초기값)

함수형 업데이트

import React, { useState } from "react";

import "./App.css";

function App() {
  const [number, setNumber] = useState(0);
  return (
    <>
      <div>Number State {number}</div>
      <button
        onClick={() => {
          // setNumber(number + 1);
          // setNumber(number + 1);
          // setNumber(number + 1);

          // 세 개 넣어도 1 올라감
          //배치성으로 처리되어 배치 업데이트가 되기 때문이다
					//(한꺼번에 변경된 걸 모아서 한 번만 반영)

          // 렌더링이 잦다 -> 성능 이슈가 있는 것
          setNumber((currentNumber) => currentNumber + 1);
          setNumber((currentNumber) => currentNumber + 1);
          setNumber((currentNumber) => currentNumber + 1);

          //   //함수형 업데이트
          // 세 개 넣으면 3 올라감
          // 명령을 모아서 순차적으로 한 번씩 실행시킴
          // 인자 부분에 현재의 state가 들어오고
          //안에서는바뀐 state를 반환하니까 각각 최신값들을 유지할 수 있어서
          // 0에서 1올라가고 1에서 2 올라가고 2에서 3 올라갈 수 있는 것,,
        }}
      >
        누르면 Up
      </button>
    </>
  );
}

export default App;

useEffect

의존성 배열(dependency array) : 이 배열에 값을 넣으면, 그 값이 바뀔 때만 useEffect 를 실행한다.

렌더링 될 때마다 특정한 작업을 수행해야 할 때 설정하는 훅

컴포넌트가 화면에 보여졌을 때

컴포넌트가 화면에서 사라졌을 때(return)

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

function App() {
  const [value, setValue] = useState("");
  useEffect(() => {
    console.log(`hello, useEffect : ${value}`);

    return () => {
      console.log("나 사라져요");
      // 컴포넌트 죽을 때 로직이 동작함
    };
  }, [value]);
  return (
    <div>
      <input
        type="text"
        value={value}
        onChange={(event) => {
          setValue(event.target.value);
        }}
        //1.input에 값을 입력
        // 2. value, 즉 state가 변경
        //3. state가 바뀌었기 때문에 -> App 컴포넌트가 리렌더링
        //4.  리렌더링 -> useEffect
        //5. 1-4번 반복

        //Dependency Array 필요
      ></input>
    </div>
  );
}

export default App;

useRef

Dom요소 접근 방법으로서의 useRef

렌더링 되자마자 특정 input태그가 focusing이 돼야하는 경우 등 Dom을 선택해야 할 상황이 생길 때 사용한다.

import React, { useRef } from "react";

function App() {
  const ref = useRef("초기값");
  //ref :reference(참조)
  console.log("ref", ref);

  ref.current = "변경값";
  console.log("ref2", ref);
  return <div>App</div>;
}

export default App;

이렇게 설정된 ref값은 컴포넌트가 계속해서 렌더링되어도 unmount 전까지 값을 유지한다!

저장공간으로서의 useRef

  • state와 비슷한 역할을 한다. 다만 state는 변화가 일어나면 다시 렌더링이 일어난다. 내부 변수들을 초기화된다.
  • ref에 저장한 값은 렌더링을 일으키지 않는다. 즉 ref의 값 변화가 일어나도 렌더링으로 인해 내부 변수들이 초기화 되는 것을 막을 수 있다.
  • 컴포넌트가 100번 렌더링 되어도 ref에 저장된 값은 유지된다.
  • state는리렌더링이 꼭필요한 값을 다룰 때 쓰면 된다.
  • ref는 리렌더링을 발생시키지 않는 값을 저장할 때 사용한다.

State 와 Ref의 차이

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

const style = {
  border: "1px solid black",
  margin: "10px",
  padding: "10px",
};

function App() {
  const [count, setCount] = useState(0);
  const countRef = useRef(0);

  const plusStateCountButtonHandler = () => {
    setCount(count + 1);
  };
  const plusRefCountButtonHandler = () => {
    countRef.current++;
  };
  return (
    <>
      <div style={style}>
        state 영역입니다. {count} <br />
        <button onClick={plusStateCountButtonHandler}>state 증가</button>
      </div>
      <div style={style}>
        ref 영역입니다. {countRef.current}
        <br />
        <button onClick={plusRefCountButtonHandler}>ref 증가</button>
      </div>
    </>
  );
}

export default App;

Dom요소 접근 방법으로서의 useRef 예시

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

function App() {
  //화면이 렌더링될 때 어떤 작업을 하고싶다! : useEffect

  const idRef = useRef("");
  const passwordRef = useRef();

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

  useEffect(() => {
    idRef.current.focus();
  }, []);

  useEffect(() => {
    if (id.length >= 10) {
      passwordRef.current.focus();
    }
  }, [id]);
  //id라는 state가 바뀔때마다 수행이 되야하기때문에 id가 들어가야함

  return (
    <>
      <div>
        아이디 :{" "}
        <input
          value={id}
          onChange={(event) => {
            setId(event.target.value);
          }}
          type="text"
          ref={idRef}
        ></input>
      </div>
      <div>
        패스워드 : <input type="password" ref={passwordRef}></input>
      </div>
    </>
  );
}

export default App;

useContext

react context의필요성

일반적으로 부모컴포넌트에서 자식 컴포넌트로 데이터를 전달해줄 때 props를 사용했다.

하지만 너무 깊어지게 되면 prop drilling이 일어난다.

prop drilling의 문제점

  1. 깊이가 너무 깊어지면 prop이 어떤 컴포넌트로부터 왔는지 파악하기 어려워진다.
  2. 어떤 컴포넌트에서 오류가 발생할 경우 추적이 힘들어져 대처가 늦을 수 밖에 없다.

이러한 문제를 해결하기 위해 react context API가 필요하고 useContext hook을 통해 쉽게 전역데이터를 관리할 수 있다.

context API 필수개념

  • createContext : context 생성
  • Consumer : context 변화 감지
  • provider : context 전달 (to 하위 컴포넌트)

주의해야 할 사항

렌더링 문제

uesContext를 사용할 때, Provider에서 제공한 value가 달라진다면 useContext를 사용하고 있는 모든 컴포넌트가 렌더링된다. 따라서 value 부분을 항상 신경써줘야 한다. → 대안 : 메모이제이션

사용 예)

components/GrandFather.jsx

import React from "react";
import Father from "./Father";
import { FamilyContext } from "../context/FamilyContext";
//GF -> Child한테 어떤 정보를 알려줘서 Child가 그 내용을 출력하도록//?!

function GrandFather() {
  const houseName = "sparta";
  const pocketMoney = 10000;
  return (
    <FamilyContext.Provider
      value={{
        houseName,
        pocketMoney,
      }}
    >
      <Father />
    </FamilyContext.Provider>
  );
}

export default GrandFather;

Father.jsx

import React from "react";
import Child from "./Child";

function Father() {
  return <Child />;
}

export default Father;

Child.jsx

import React, { useContext } from "react";
import { FamilyContext } from "../context/FamilyContext";

const style = {
  color: "red",
  fontWeight: "900",
};

function Child() {
  const data = useContext(FamilyContext);
  console.log(data);
  return (
    <div>
      나는 이 집안의 막내예요. <br />
      할아버지가 우리집 이름은 <span style={style}>{data.houseName}</span>이라고
      하셨어요. <br />
      게다가 용돈도 <span style={style}>{data.pocketMoney}</span>원 만큼이나
      주셨어요!
    </div>
  );
}

export default Child;

App.jsx

import React from "react";
import GrandFather from "./components/GrandFather";

function App() {
  return <GrandFather/>
}

export default App;

context/FamilyContext.js

import { createContext } from "react";

export const FamilyContext = createContext(null);

0개의 댓글