useState 실수하기 좋은 부분 총정리

미마모코딩·2022년 10월 6일
0

리액트 기본기

목록 보기
2/6
post-thumbnail

useState

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

function App() {
  const [number, setNumber] = useState(0);

  const increase = () => {
    setNumber(number + 1);
  };

  const increaseAsync = () => {
    setTimeout(() => {
      setNumber(number + 1);
    }, 2000);
  };
  return (
    <div>
      <button onClick={increase}>increase</button>
      <button onClick={increaseAsync}>increaseAsync</button>
      <h1>{number}</h1>
    </div>
  );
}

export default App;

우리는 useState를 통해 상태를 만들어 동적으로 상태를 관리한다.

위 코드에서 increase함수를 만들었고 버튼에 함수를 달아놓았다.

number가 set함수를통해 +1 씩 증가할 것이다.

하지만 increaseAsync 비동기 증가함수는 어떻게 될까?

버튼을 두 번 클릭해 number의 값이 2로 되게끔 만든다.

현재 number는 2이고 비동기증가 함수를 누르면 2초후에 1이 늘어난다.

2초가 지나기전에 5번을 더 누르면 어떻게 될까?

number은 7이되고 2초가 지난시점에 갑자기 3으로 돌아온다.

왜 이런 예측 불가능한 상황이 이루어질까? 내부적으로 어떻게 동작하길래?

비동기로 증가하는 함수는 눌렀을때 이전 스테이트의 값을 기억하고 있다.

그렇기때문에 2초가 지나기전에 7을 만들더라도 비동기함수의 입장에선 2를 보고있었기때문에 +1을
해주어 자신의 역할을 다 한것이다.

그렇다면 위 코드를 어떻게 개선 할 수 있을까?

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

function App() {
  const [number, setNumber] = useState(0);

  const increase = () => {
    setNumber(number + 1);
  };

  const increaseAsync = () => {
    setTimeout(() => {
      setNumber((currentNumber)=>currentNumber+1);
    }, 2000);
  };
  return (
    <div>
      <button onClick={increase}>increase</button>
      <button onClick={increaseAsync}>increaseAsync</button>
      <h1>{number}</h1>
    </div>
  );
}

export default App;

위와같이 비동기 코드에서 set함수안에 함수 자체를 전달해서 개선하는 방법이 있다.

useState 객체 , 배열 업데이트

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

function App() {
  const [inputValue, setInputValue] = usesState("");
  const [user, setUser] = useState({
    name: "mimamo",
    email: "robo888@naver.com",
    images: ["profile.png", "cover.png"],
  });

  const userNameChangeFun = () => {
    setUser((user.name = inputValue));
  };
  console.log(user);

  return (
    <div>
      <h2>User:</h2>
      <input
        onChange={(e) => setInputValue(e.target.value)}
        placeholder="write there!"
      ></input>
      <button onClick={userNameChangeFun}>UserNameChange</button>
      <span>user name : {user.name}</span>
    </div>
  );
}

export default App;

위와 같이 user객체를 내가 적은 인풋값으로 대체할때는 어떻게 해야할까?

위 코드가 과연 해결책일까? 아니다

배열 또는 객체의 자료구조 형태는 레퍼런트 타입이기 때문에 즉 안에 내용이 바뀌어도 useState는 데이터를 감싼 [] , {} 이 껍데기들이 바뀌지 않는 한 업데이트 되지 않는다.

간단하게 콘솔에 const a = [] const b = [] a===b 를 찍어보면 false가 나오는 이유에 대해 생각해보면 받아들이기 쉬울것이다.

그렇기 때문에 위에 코드를 개선해보면

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

function App() {
  const [inputValue, setInputValue] = usesState("");
  const [user, setUser] = useState({
    name: "mimamo",
    email: "robo888@naver.com",
    images: ["profile.png", "cover.png"],
  });

  const userNameChangeFun = () => {
    setUser((prev) => ({ ...prev, name: inputValue }));
  };
  console.log(user);

  return (
    <div>
      <h2>User:</h2>
      <input
        onChange={(e) => setInputValue(e.target.value)}
        placeholder="write there!"
      ></input>
      <button onClick={userNameChangeFun}>UserNameChange</button>
      <span>user name : {user.name}</span>
    </div>
  );
}

export default App;

spread operator를 사용하여 위처럼 setUser 함수에 이름을 오버라이딩해 업데이팅 시켜야 useState는 껍데기가 바뀌었네? 라고 판단해 업데이트를 해준다.

useState 입력양식 폼이 많을때 컨트롤 하는법

Fe개발자가 하는 역할중에 중요한 개념이다.

입력양식을 받아 만약 name : userName : address : email :city : country : 이런식으로 많은 인풋창을 구현하고 하나하나 useState로 인풋을 관리하기엔 가독성과 효율이 너무나도 크게 떨어질것이다.

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

function App() {
  const [user, setUser] = useState({
    name: "",
    surname: "",
    username: "",
    email: "",
    password: "",
    country: "",
    city: "",
    address: "",
  });
  const handleChange = (e) => {
    setUser((prev) => ({ ...prev, [e.target.name]: e.target.value }));
  };

  return (
    <div>
      <input onChange={handleChange} name="name" placeholder="name"></input>
      <input
        onChange={handleChange}
        name="surname"
        placeholder="surname"
      ></input>
      <input
        onChange={handleChange}
        name="username"
        placeholder="username"
      ></input>
      <input onChange={handleChange} name="email" placeholder="email"></input>
      <input
        onChange={handleChange}
        name="password"
        placeholder="password"
      ></input>
      <input
        onChange={handleChange}
        name="country"
        placeholder="country"
      ></input>
      <input onChange={handleChange} name="city" placeholder="city"></input>
      <input
        onChange={handleChange}
        name="address"
        placeholder="address"
      ></input>
      <button>submit</button>
    </div>
  );
}

export default App;

위와같은 방식은 한번에 여러 인풋들을 모두 컨트롤 할 수 있게된다.

어떻게 되는것일까?

해답은 인풋속성의 name에있다 . 우리는 그 name을 지정하고 이용해
[e.target.name]이란 대괄호 표기법으로 name의 키값에 접근하고 벨류를 우리가 원하는 value로 설정하는 것이다.

오늘은 useState의 대해 딥하게 알아보았다. 모두 코드를 조금 집중적으로 보고 특징과 포인트를 잘 기억하면 좋겠다.

0개의 댓글