패스트 캠퍼스 MGS 3기 - 5월 18일(useState)

JY·2022년 5월 18일
0

state


컴포넌트 안에서 관리되는 유동적인 데이터이다.

1. useState


[value, setterFunc] = useState()

🤔 리액트 컴포넌트가 다시 렌더되는 조건
함수 컴포넌트가 렌더된다. = 함수 컴포넌트가 다시 실행되었다.

1. prop이 업데이트 된 경우
2. state가 업데이트 된 경우
3. 부모 컴포넌트가 다시 렌더된 경우 (1, 2번과 같은 이유 등으로 리렌더링 된 경우) 👉 이 경우 자식 컴포넌트도 다시 렌더링된다.

🤔 update를 판단할 때 주의할 점(deep vs shallow)

  • Primitive Type인 경우 값까지 비교
  • Reference Type(Object, Array 등)인 경우 참조까지만 비교 👉 안쪽에 있는 값까지 비교하진 않는다!

    다음 코드에서 리액트는 left의 값을 바꿔도 렌더를 다시 해야 한다고 생각하지 않는다. (레퍼런스 타입이므로) left[0]의 값을 바꾼다고 해도 left 자체는 그대로이므로 렌더하지 않는 것이다.

    right 값을 먼저 입력하고, left를 입력하면 결과가 나오지 않는다.
    그런데 left를 먼저 입력하고, right를 입력하면 결과가 나오는데, 이때는 right(프리미티브 타입) 값이 변경되면 렌더되므로 값이 나오게 되는 것이다.
    (setLeft(left)를 하더라도 주소값이 변경되지 않았으므로 렌더는 되지 않는다!)


    따라서 value의 값을 직접적으로 변경하는 것이 아니라, setter 함수를 통해 값을 변경해야 한다. (useState로 값을 바꾼다.(❌), setter 함수로 값을 바꾼다.(⭕))
    또한, 레퍼런스의 타입의 경우 주의해야 한다!

2. state 업데이트의 비동기성



비동기성때문에 setNum(num+1) 첫 번째 줄에서 num+1이 처리되기 전에 두 번째 줄로 넘어갈 수도 있다. 우리가 기대하는 것은 <1+1 → 2+1 → 3+1, 결과값: 4>이지만, 이것이 아닌 <1+1 → 1+1 → 1+1, 결과값: 2>이 된다.

그래서! setNum이 호출될 당시의 num 값을 콜백함수 형태로 넘겨준다. setNum(prev => prev + 1) (setState는 비동기로 작동하므로 순서가 필요할 경우 콜백함수 형태로 작동해야 하는 것.)

이때, 한 줄씩 실행되는 것이 아니라 같은 스테이트라도 매우 짧은 시간 안에 업데이트가 일어날 시 리액트는 한번에 묶어서 처리한다.(= 렌더가 한 번만 일어난다.) → 배치 업데이트(Batch update)

setNum 자체가 동기적인 것이 아니라 함수들끼리 동기적으로 작동하는 것이다!

3. Hooks?


  • 함수형 컴포넌트 안에서 state, side effect를 다루기 위해 사용하는 함수이다.
  • 일반적으로 'use'로 시작한다.
  • ex. useState, useEffect, useMemo...

4. 실습


👩‍💻 01

import React, {useState} from 'react'

export default function Calculator() {
  const [result, setResult] = useState(0);
  const [num1, setNum1] = useState(0);
  const [num2, setNum2] = useState(0);
  
  return (
    <>
      <input type="number" value={num1} onChange={(event) => setNum1(parseInt(event.target.value))} />
      +
      <input type="number" value={num2} onChange={(event) => setNum2(parseInt(event.target.value))}/>
      =
      <input type="number" disabled value={result} />
      <button type="button" onClick={() => setResult(num1+num2)}>계산</button>
    </>
  )
}

🤔 re-render는 언제 될까?
처음 실행했을 때 1번!
input에 값이 입력될 때마다!
'계산' 버튼을 클릭했을 때 1번!

🤔 readonly vs disabled
둘 다 읽기만 가능하고 값을 변경할 수 없다.
하지만, disabledform으로 값을 보낼 때 값이 전송되지 않는다.


👩‍💻 02

다음 코드를 변경해서 버튼을 클릭할 때마다 'hellojinbye'가 출력되도록 하자.

const names = [{
  name: 'hello',
}, {
  name: 'jin',
}, {
  name: 'bye',
}];

const App = () => {
  const [result, setResult] = React.useState<string[]>([]);
  return (
    <>
      { /*result*/ ['hello', 'jin', 'bye']}
      <button type='button' onClick={() => {}} />
    </>
  );
}

import React, {useState} from 'react';

const names = [{
  name: 'hello',
}, {
  name: 'jin',
}, {
  name: 'bye',
}];

const App = () => {
  const [result, setResult] = useState([]);

  return (
    <>
      {result}
      <button type='button' onClick={() => {
        // setResult([...result, ...names.map(({name})=>name)]);
        setResult(
          [...result, ...names.map((element) => {return element.name})]
          );
      }} >버튼</button>
    </>
  );
}

export default App;


🤔 setState를 이용해 배열을 state로 관리
step1. 배열을 하나 새로 만든다. >> 새로운 메모리 주소를 가지고 있는 배열.
step2. 배열에 대해서 작업을 함. let temp = [...state]
step3. setState[...아까 만든 배열]

profile
🙋‍♀️

0개의 댓글