2023-02-14(React-hook)

박준혁·2023년 2월 14일
0
✅ useState
✅ useEffect
✅ uesRef
✅ useContext

useState

  • 가장 기본적인 hook이다
  • 함수형 컴포넌트 내에서 가변적인 상태를 갖게 한다.
  • 사용법 : const [state, setState] = useState(초기값)
  • 사용법 해석 : useState가 return하는 값이 배열이다. 그 배열을 staet, setState로 구조분해할당으로 받은 것 분이다. 배열의 return값은 초기값으로 지정해놓은 변수(state)가 있고 그 state를 변경(컨트롤)할 수 있는 setState. 이렇게 두 개의 배열로 이루어져있다.

#useState의기존방식

 const [number, setNumber] = useState(0);
  const buttonClick = () => {
    setNumber(number + 1)
  };
  return (
    <>
      <div>Number : {number}</div>;<button onClick={buttonClick}>버튼</button>
    </>
  );

함수형 업데이트

함수의 인자부분()에는 현재 state를 가져올 수 있다(여기선 currentNumber)

  const [number, setNumber] = useState(0);
  return (
    <>
      <div>Number : {number}</div>;
      <button onClick={() => {                      //기본형에서 함수형으로 변환
          setNumber((currentNumber) => {
            return currentNumber + 1;
          });
        }}
      >버튼</button>
    </>
  );
onClick={() => {setNumber((currentNumber) => currentNumber+1)}}

{/*return문이 한 줄일경우 이렇게 줄여서 쓸 수 있다*/}

✅✅차이점은 뭘까?
일반 업데이트 방식 : [배치성으로 처리된다]]
리액트에서 렌더링을 하기 위해서 state를 파악하는데 그 state를 파악하는 방법이 "배치업데이트" 한꺼번에 변경된 내용들을 모아서 한 번만 실행을 한다. setNumber을 여러번 해도 이거를 한 꺼번에 모으기 때문에 => 똑같은 건 한 개로 친다

  <div>Number : {number}</div>;<button onClick={
              setNumber(number + 1)
              setNumber(number + 1)
              setNumber(number + 1)}       --------->count가 1씩만 증가
              >버튼</button>

함수형 업테이트 방식 : 명령들을 모아서 각각 한 번씩 실행을 시킨다. 세 번을 동시에 실행을 시키면 명령을 모아서 순차적으로 한 번씩 한 번씩 시킨다
이유 : 인자 부분에 현재 상태의 state가 들어오는데 바뀐 state를 반환하고 그 다음엔 바뀐 값(즉 현재 state)에서 또 바뀐 값을 반환하고 ...이것을 반복한다.----->최신값 유지

      <button onClick={() => {
                  setNumber((currentNumber) => currentNumber + 1)
                  setNumber((currentNumber) => currentNumber + 1)
                  setNumber((currentNumber) => currentNumber + 1)
                  ---->카운트가 3씩올라감

❓❓그럼 리액트 환경에서 "[배치성]"을 쓰는 이유는?
->렌더링이 잦다: 성능에 이슈가 있다. 그러기때문에 불필요한 렌더링을 피하기 위해 한꺼번에 요청사항을 모아서 한 번만 처리하는 게 렌더링을 줄일 수 있는 방법이기에 리액트에서 사용함


useEffect

[useEffect] : 화면이 렌더링이 될때마다 , 특정한 작업을 수행해야 할 때 ->설정하는 hook
ex) 화면이 렌더링 될 때 콘솔을 찍어야한다거나, alert 등을 수행하게 하는 hook
===화면이 렌더링 될 때 어떤 작업을 하고 싶다===
===> [화면이 렌더링 될 때마다 출력되는 hook이며 dependency array에 뭔가 들어가면 그 뭔가의 state가 바뀔때마다 내부의 로직이 수행된다. ] --> 빈 값이면 처음 mount(호출)될 때만 실행된다.

-->1. 어떤 컴포는트가 화면에서 보일때
2. 사라졌을 때 무언가 실행을 하고 싶다면 (return)
그때 useEffect를 사용한다

const [value, setVlue] = useState('');
  useEffect(() => {
    console.log('hello');
  });
  return (
    <div>
      <input type="text" value={value} onChange={(e) => setVlue(e.target.value)}/>
    </div>
  );

순서 :
1. input에 값을 입력한다면
2. value, 즉 state가 변경된다
3. state가 바뀌었기 때문에 app컴포넌트가 리렌더링 된다.
4. 리렌더링 되면-> useEffect()가 다시 실행
1~4 반복
++value라는 state의 어떠한 값{value}을 input에 입력할 때마다 value라는 state에 저장이 된다. ----> input에 값을 입력할 때마다 렌더링이 다시 되고 있다.

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

사용법 : 함수가 끝나는 부분 뒤에 두 번째 인자로 넣어준다
배열에 어떤 값이 바뀌면 hello가 출력이 되게 할 지를 정하면 된다.
현재 []빈 배열이기때문에 : 어떤 값을 입력하던지간에, 어떤 값이 변하던지 간에 의존성 배열엔 값이 없기 때문에 어떤 state가 변해도 hello는 화면이 처음 로딩 될 때만 동작한다.

useEffect(() => {
    console.log('hello');
  }, [])                  -------->콘솔엔 처음 hello만 찍히고 이제 안 찍힌다

화면에서 없어졌을 때도 동작을 하는데 --> clean up

  useEffect(() => {
      console.log('hello');
      return () => {
          console.log("나 사라져요")
      }
  }, []);
 -----------> useEffect안에 body부분에 return문을 함수형태로 쓰면 된다

✅useEffect는 콜백함수로 들어가는데~
콜백함수 : 매개변수로 함수가 들어가는 것

useEffect(function() {})  //이런 형태

useRef

✅ref = reference참조
✅ref용도
1. [저장 공간]으로서의 useRef
2. [DOM요소 접근 방법으로서의 useRef] : DOM요소에 접근할 수 있도록 도와주는 HOOK
ex) 네이버에 들어가면 네이버 창에 focusiing되어 있다(이렇게 focusing되어야하는 특정 DOM을 선택해야하는 상황이 생기는데 이럴경우 useRef사용하고 변수처럼 쓰기위해서도 사용한다. )

const ref = useRef('초기값');        --->콘솔 : ref{current : '초기값'}
  console.log('ref', ref);
  
  ref.current = '변경값';            ---->콘솔 : ref{current : '변경값'}
  console.log('ref2', ref);
	```                                 
=>즉 ref의 키 값은 변경 가능하다(객체로 표현이 된다.)

⭐⭐이렇게 설정된 ref값은 컴포넌트가 계속해서 렌더링 되어도 unmount전까지(즉 컴포넌트가 죽기 전까지) 값을 유지한다.⭐⭐
-------
✅state와 ref의 차이점
- state 
state는 ref와 비슷한 역할을 한다. 하지만 [state는 변화가 일어나면 다시 렌더링이 일어난다. 이때 내부 변수들은 초기화가 된다.]
- ref
ref에 저장한 값은 렌더링을 일으키지 않는다. 즉 ref의 값 변화가 일어나도 렌더링으로 인해 냅주 변수들이 초기화 되는 것을 막을 수 있다.([ref는 값이 변해도 렌더링이 안 일어나기에 초기화도 막음])
--> 즉 컴포넌트가 100번 렌더링이 이러나도 ref에 저장한 값은 유지된다.

🍀즉 state는 리렌더링이 꼭 필요한 값을 다룰 때 쓰면 된다
🍀즉 ref는 리렌더링을 발생시키지 않는 값을 저장할 때 사용한다.


```js
STATE
 //count를 누를때마다 숫자가 올라가는데 화면이  렌더링이 계속해서 다시 일어나고있다
  const pulsStateCountButtonHandler = () => {
    setCount(count + 1);
  };
useRef
//count를 눌러도 렌더링이 되지 않는다
 const pulsRefCountHandler = () => {
    countRef.current++;
    console.log(countRef.current);


      <div style={style}>                     ===> 스타일을 변수로 넣어서 편하게함
        ref영역입니다, {countRef.current} <br />   -==> 객체이고 초기값에 접근하려고
        <button onClick={pulsRefCountHandler}>ref 증가</button>
      </div>

  };

✅DOM
Document Object Model로 웹 페이지에 대한 인터페이스입니다. 기본적으로 여러 프로그램들이 페이지의 콘텐츠 및 구조 , 그리고 스타일을 읽고 조작할 수 있또록 api를 제공합니다.

DOM예시

ID아이디로 Focusing되게끔

const idRef = useRef('');
useEffect(() => {
    idRef.current.focus();


    아이디 :{' '}
        <input type="text" ref={idRef} />
  }, [id]); //id라는 state가 바뀔때마다 얘가 수행되어야하니 id를 넣어준다

✅응용 예시 로그인 값이 특정 개수를 넘길 때 비밀번호로 넘어가게
==1==, useState를 쓰고
id 와 pw가 타이핑 되어서 값이 변경 되어야하니까
==2==, useEffect를 쓰고
id의 값과 pw의 값이 리렌더링 됨에 따라 수행해야하는 어떤 것(포커싱되는 것)이 있기에
==3==, useRef를 써야하는 이유
아이디가 포커싱 되게 해줘 즉 얘가 focus될 수 있도록 얘를 잡아줘야 한다 지정을 해줘야한다 이에 대한 ==레퍼런스(참조, 언급,가리킴)==를 갖고 있어야한다 ==id의ref니까 idRef==

const [id, setId] = useState('');
const [pw, setPw] = useState('') 
const idRef = useRef('');
const pwRef = useRef('');

  useEffect(() => {
    idRef.current.focus();
  }, [id]); //id라는 state가 바뀔때마다 얘가 수행되어야하니 id를
  
  useEffect(() => {
    if (id.length >= 10) {
      pwRef.current.focus();
    }
    console.log('안녕');

  });
   return (
    <>
      <div>
        아이디 :{' '}
        <input value={id} onChange={(e) => setId(e.target.value)} type="text" ref={idRef} />
      </div>
      <div>
        비밀번호 :{' '}
        <input alue={pw} onChange={(e) => setPw(e.target.value)} type="password" ref={pwRef} />
      </div>
    </>
  );
}

✅리렌더링

버튼을 눌렀을 때 숫자가 올라가야 된다라는 거는 그 숫자라는 부분이 올라가는 게 보여야되는거니까 ->렌더링이 다시 일어난다->렌더링이 필요한 것


useContext

✅전역적으로 사용되는 어떠한 것을 표현할 때 context란 말을 쓴다

  • createContext

    context생성
  • consumer

    context 변화 감지
  • Prvider

    context 전달(하위 컴포넌트에게로)

props drilling이 너무 많을 경우 useContext를 쓴다(굳이 필요 없는 중간 컴포넌트를 거치는 게 비효율적이라서)

useContext 사용 예시

가져다 쓸 cotext : Familycomponent
import { createContext } from 'react';
export const FamilyContext = createContext(null);  
// 나중에 privider로 주입하는 그 하위 컴포넌트 들에서 사용할 수 있는 context가 완성될 거다
// 가져다 쓰면 된다
할아버지 컴포넌트
import React from 'react';
import Father from './Father';
import { FamilyContext } from '../Context/FamiluContext';
//할아버지가 --> Child한테 어떤 정보를 알려줘서 child가 그 내용을 출력하도록
function GrandFather() {
  const houseName = '스파르타';
  const pocketMoney = 10000; 
  return (
    <FamilyContext.Provider
      value={{
        houseName,       ------>프로퍼티로 value를 넘겨줘야하는데 객체다
        pocketMoney,
      }}>
      <Father />;
    </FamilyContext.Provider>
  );
}
export default GrandFather;

//props가 필요가 없는 이유는 props로 값을 내려주는 게 아니라 우리는 이제contex만든 걸 가지고 외부로 접근하니까 <그러므로 props전부 지워준다>

//familyContext를 임포트 해왔으니 이제 provider을 적용해야한다 (제공자)
(현재보다 하위 컴포넌트에게 제공한다)
//해석 : father컴포넌트 밑으로 이걸 제공해준다
child컴포넌트
import React, { useContext } from 'react';
import { FamilyContext } from '../Context/FamiluContext';
function Child() {
  const data = useContext(FamilyContext);
  console.log('data', data); 
  return (
    <>
      <div>나는 이 집안의 막내에요</div>; 할아버지가 우리 집 이름을<span>{data.houseName}</span>
      이라했다 <br />
      게다가 용돈도 <span>{data.pocketMoney}</span>원만큼 줬어요 <br />
    </>
  );
}
export default Child;  
//context로부터 데이터를 받아와야하는데 그 방법은 
 const data = useContext(FamilyContext)로 받아와진다.

그림 예시
![[Pasted image 20230211033534.png]]

props로내려준 값을 쓴 게 아니라 context를 이용해서 값을 받아왔다.

✅주의 사항
렌더링 문제
useContext를 사용할 때, [provider에서 제공한 value가 달라진다면 useContex를 사용하고 있는 모든 컴포넌트가 리렌더링 된다] 따라서 value 부분은 항상 신경 ㄱㄱ(엄청 비효율적임)
-->메모이제이션(기억)이 해결방안

profile
"열정"

0개의 댓글