React/React 정리

React 문법 정리 2 - useState, input 상태관리, 불변성

daramG 2023. 4. 6. 16:59

https://react.vlpt.us/basic/07-useState.html

 

7. useState 를 통해 컴포넌트에서 바뀌는 값 관리하기 · GitBook

7. useState 를 통해 컴포넌트에서 바뀌는 값 관리하기 지금까지 우리가 리액트 컴포넌트를 만들 때는, 동적인 부분이 하나도 없었습니다. 값이 바뀌는 일이 없었죠. 이번에는 컴포넌트에서 보여줘

react.vlpt.us

 

 

useState 를 통해 컴포넌트에서 바뀌는 값 관리하기

 

리액트 16.8 에서 Hooks 라는 기능이 도입되면서 함수형 컴포넌트에서도 상태를 관리할 수 있게 되었다.

useState 라는 함수는 리액트의 Hooks 중 하나이다.

 

 

https://learnjs.vlpt.us/basics/05-function.html#%ED%99%94%EC%82%B4%ED%91%9C-%ED%95%A8%EC%88%98

// 화살표 함수

const add = function(a, b) {
  return a + b;
};

// function 키워드 대신에 => 문자를 사용해서 함수를 구현
const add = (a, b) => {
  return a + b;
};

// 코드 블록 내부에서 바로 return 을 하는 경우 return 생략
const add = (a, b) => a + b;

console.log(add(1, 2));

 

 

> +1, -1 버튼 누를 시에 console.log 만 띄우기

 

App.js

import React from 'react';
import Counter from './Counter';

function App() {
  return (
    <Counter></Counter>
  );
}

export default App;

 

Counter.js

import React from 'react';

function Counter() {
    const onIncrease = () => {
        console.log("+1");
    }
    const onDecrease = () => {
        console.log("-1");
    }
    // onClick={onIncrease()} X
    // 이렇게하면 렌더링되는 시점에서 값이 호출되기 때문
    // 이벤트 설정 시에는 함수타입의 값을 넣어주어야 한다.
    return (
        <div>
            <h1>0</h1>
            <button onClick={onIncrease}>+1</button>
            <button onClick={onDecrease}>-1</button>
        </div>
    );
}
export default Counter;

 

 

동적인 값 끼얹기, useState

컴포넌트에서 동적인 값을 상태(state)라고 부른다.

리액트에 useState라는 함수가 있는데 이것을 사용하면 컴포넌트에서 상태를 관리할 수 있다.

 

App.js

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

function App() {
  return <Counter></Counter>;
}

export default App;

 

Counter.js

import React, { useState } from "react";

function Counter() {
  // [현재 상태, Setter 함수]
  // Setter 함수는 파라미터로 전달 받은 값을 최신 상태로 설정
  const [number, setNumber] = useState(0);

  const onIncrease = () => {
    setNumber(number + 1);
  };
  const onDecrease = () => {
    setNumber(number - 1);
  };
  // onClick={onIncrease()} X
  // 이렇게하면 렌더링되는 시점에서 값이 호출되기 때문
  // 이벤트 설정 시에는 함수타입의 값을 넣어주어야 한다.
  return (
    <div>
      <h1>{number}</h1>
      <button onClick={onIncrease}>+1</button>
      <button onClick={onDecrease}>-1</button>
    </div>
  );
}
export default Counter;

 

실행결과 )

 

 

함수형 업데이트

 

사용 이유, 원리 : https://garve32.tistory.com/39

 

[React] useState의 비동기 처리와 함수형 업데이트

#1. setState는 비동기로 동작한다 아래와 같이 동작하는 코드를 보자. 하나는 숫자를 1씩 증가시키는 버튼이고, 하나는 숫자를 1씩 감소시키는 버튼이다. import React, { useState } from "react" function App() {

garve32.tistory.com

 

아까 전엔 Setter 함수를 사용할 때, 업데이트 하고 싶은 새로운 값을 파라미터로 넣어줬다.

그 대신 기존 값을 어떻게 업데이트 할 지에 대한 함수를 등록하는 방식으로 값을 업데이트 하자.

값을 전달하는 것이 아닌 업데이트된 최신의 state와 함께 함수를 전달하는 방법이다.

 

 

App.js

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

function App() {
  return <Counter></Counter>;
}

export default App;

 

Counter.js

import React, { useState } from "react";

function Counter() {
  // [현재 상태, Setter 함수]
  // Setter 함수는 파라미터로 전달 받은 값을 최신 상태로 설정
  const [number, setNumber] = useState(0);

  const onIncrease = () => {
    setNumber((num) => num + 1);
  };
  const onDecrease = () => {
    setNumber((num) => num - 1);
  };
  // onClick={onIncrease()} X
  // 이렇게하면 렌더링되는 시점에서 값이 호출되기 때문
  // 이벤트 설정 시에는 함수타입의 값을 넣어주어야 한다.
  return (
    <div>
      <h1>{number}</h1>
      <button onClick={onIncrease}>+1</button>
      <button onClick={onDecrease}>-1</button>
    </div>
  );
}
export default Counter;

 

 

 

input 상태 관리하기

리액트에서 사용자가 입력할 수 있는 input 태그의 상태 관리

input에 입력하는 값이 하단에 나타나게 하고, 초기화 버튼을 누르면 input이 비워지게 구현

 

이벤트 등록 함수에서는 이벤트 객체 e를 파라미터로 받아와 사용할 수 있다.

e.target은 이벤트가 발생한 DOM인 input DOM이고,

e.target.value는 이 DOM의 value, 즉 input에 입력한 값을 의미한다.

 

App.js

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

function App() {
  return <InputSample />;
}

export default App;

 

InputSample.js

import React, { useState } from "react";

function InputSample() {
  const [text, setText] = useState(" ");
  const onChange = (e) => {
    setText(e.target.value);
  };
  const onReset = () => {
    setText(" ");
  };
  return (
    <div>
      <input onChange={onChange} value={text} />
      <button onClick={onReset}>초기화</button>
      <div>
        <b>값: {text}</b>
      </div>
    </div>
  );
}

export default InputSample;

 

 

 

여러개의 input 상태 관리하기

 

//

onChange

- 변할때마다 실행된다.

- 주로 input 태그의 이벤트 값을 받아와 name과 value를 비구조화 할당을 통해 추출한다.

onClick

- 클릭되면 실행된다.

 

비구조화 할당

- 배열이나 객체의 속성 혹은 값을 해체하여 그 값을 변수에 각각 담아 사용하는 자바스크립트 표현식

https://learnjs.vlpt.us/useful/06-destructuring.html

// 기존 배열값 해체

const animalList = ['DARAMG', 'PINKBEAN', 'RAICHU'];

const daramg = animalList[0];
const pinkbean = animalList[1];
const raichu = animalList[2];

console.log(daramg);
console.log(pinkbean);
console.log(raichu);
// 배열의 비구조화 할당 방식

const [daramg, pinkbean, raichu] = ['DARAMG', 'PINKBEAN', 'RAICHU'];
console.log(daramg);
console.log(pinkbean);
console.log(raichu);

// 객체의 비구조화 할당 방식

const { daramg, pinkbean, raichu } = {
  daramg: 'DARAMG',
  pinkbean: 'PINKBEAN',
  raichu: 'RAICHU'
};
console.log(daramg);
console.log(pinkbean);
console.log(raichu);

 

 

//

리액트 상태에서 객체를 수정해야 할 때는 

inputs[name] = value; 이런 식으로 수정해서는 안된다.

새로운 객체를 만들어 새로운 객체에 변화를 주고 이를 상태로 사용해야 한다.

setInputs({
    ...Inputs,
    [name] : value
});

이러한 작업을 불변성을 지킨다 라고 한다.

불변성을 지켜야만 리액트 컴포넌트에서 상태가 업데이트 됐음을 감지할 수 있고 이에 따라 필요한 리렌더링이 진행된다.

만약 inputs[name] = value; 이런 식으로 수정하면 값을 변경해도 리렌더링이 되지 않는다.

또한 리액트에서 불변성을 지켜야만 컴포넌트 업데이트 성능 최적화를 제대로 할 수 있다.

(배열의 경우 push, splice, sort 등의 함수를 사용하면 안되고

만약 사용하려면 기존의 배열을 한번 복사하고 나서 사용해야 한다.)

 

리액트의 불변성과 지켜야 할 이유

https://hsp0418.tistory.com/171

 

리액트 불변성이란 무엇이고, 왜 지켜야 할까?

들어가면서 리액트와 불변성의 연관 관계는 리액트가 지향하는 함수형 프로그래밍의 특징에서 발견할 수 있습니다. 함수형 프로그램밍의 특징 중 하나가 순수함수를 사용하는 것인데, 여기서

hsp0418.tistory.com

 

불변성의 의미 : 메모리 영역에서 값이 변하지 않는다.

let array = [1, 2, 3, 4];
array.push(5); // 불변성을 지키지 않는다.

array = [1, 2, 3, 4, 5]; // 불변성을 지킨다.

array.push(5); 는 원본 배열을 수정하면서 불변성을 지키지 않고 있다.

반면 array = [1, 2, 3, 4, 5]; 는 원본 배열을 수정하는 것이 아니라 새 참조값을 가진 새로운 배열을 할당하므로

불변성을 지켜주고 있다.

 

불변성을 지켜야 할 이유 :

리액트가 상태 업데이트를 하는 원리 때문이다.

1. 리액트는 상태값을 업데이트 할 때 얕은 비교(이전 참조값과 현재 참조값만을 비교)를 수행한다.

이런 이유로 배열이나 객체를 업데이트 할 때 setState([...state, newState]) 이런 식으로

새로운 참조값을 가진 배열이나 객체를 생성하는 것이다. 불변성을 지킴으로써 리액트는 상태변화를 감지할 수 있다.

얕은 비교는 계산 리소스를 줄여주기 때문에 리액트는 효율적으로 상태를 업데이트 할 수 있다.

2. 사이드 이펙트를 방지할 수 있다.

외부에 존재하는 원본데이터를 직접 수정하지 않고, 원본 데이터의 복사본을 만들어 값을 사용하기에

예상치 못한 오류를 사전에 방지할 수 있다.

이렇게 리액트는 불변성을 지킴으로써 효과적인 상태 업데이트와 사이드 이펙트를 방지하는 이점을 얻고 있다.

 

리액트는 spread, map, filter, slice, reduce 등 새로운 배열을 반환하는 메소드를 활용해 불변성을 지킨다.

https://daramgda.tistory.com/251

 

#2 React 배열, 배열 수정

강의 링크 : https://www.youtube.com/watch?v=U7zNZrLhhlA&list=PL93mKxaRDidEfLM0I_FFb-98vfAQgXT82&index=4 https://www.youtube.com/watch?v=IQovah5bz3Q&list=PL93mKxaRDidEfLM0I_FFb-98vfAQgXT82&index=5 해당 게시글은 위 링크의 강의를 보고 해

daramgda.tistory.com

 

 

여러 개의 input 상태 관리

 

App.js

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

function App() {
  return <InputSample />;
}

export default App;

 

InputSample.js

import React, { useState } from "react";

function InputSample() {
  // useState에서 문자열이 아니라 객체 형태의 상태 관리
  const [inputs, setInputs] = useState({
    name: " ",
    nickname: " ",
  });
  // 객체의 비구조화 할당
  // 그 부분은 input의 value값을 유지하기 위함
  // state가 변하면 렌더링이 다시 일어나고, 그 때마다 input에 지정된 value값이 없다면 입력했던 값이 지워짐
  const { name, nickname } = inputs;

  const onChange = (e) => {
    // e.target은 이벤트가 발생한 DOM인 input DOM
    const { name, value } = e.target; // name, value 추출
    setInputs({
      ...inputs,
      [name]: value, // name 키를 가진 값을 value로 설정
    });
  };
  const onReset = () => {};
  return (
    <div>
      <input name='name' placeholder='이름' onChange={onChange} value={name} />
      <input
        name='nickname'
        placeholder='닉네임'
        onChange={onChange}
        value={nickname}
      />
      <button onClick={onReset}>초기화</button>
      <div>
        <b>값: </b>
        {name} ({nickname})
      </div>
    </div>
  );
}

export default InputSample;