React | state, useState, setState

33764 단어 ReactReact

keyword state, useState(), setState(), re-rendering

요약

useState, setState 사용 장점

데이터(값)를 업데이트시키고 메인 컴포넌트를 리렌더링함
즉, state가 바뀌면 리렌더링을 자동으로 발생시킴.

state 상태변경값 변수선언 -> Event Listen -> Event Update -> UI display


state

state

기본적으로 데이터가 저장되는 곳


state, event listening, update, re-rendering

어떻게 하면 React.js 어플리케이션에서 바뀌는 데이터값을 담아줄 수 있을까?

(1) 가변하는 데이터 저장 변수 + (2) 이벤트 리스닝 (3) 이벤트 업데이트 + (3) 새로고침(리렌더링) 방법

    1. (bad way) 일반 변수선언 + 실행 함수 + 리렌더링 함수 = 수작업 업데이트
    1. (best way) useState 변수 선언 + 실행 함수 = 자동 업데이트

  1. (bad way) 일반 변수선언 + 실행 함수 + 리렌더링 함수 = 수작업 업데이트

변수를 JSX함수에 전달하는 방법? {변수명}

예제 카운트업 함수 만들기

<!DOCTYPE html>
<html lang="en">
  <head> </head>
  <body>
    <div id="root"></div>
  </body>
  <!-- react.js-->
  <script src="https://unpkg.com/react@17/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  <script type="text/babel">
    const root = document.getElementById("root");
    let counter = 0;

    function countUp() {
      counter = counter + 1;
      render();
    }

    function render() {
      ReactDOM.render(<Container />, root);
    }

    function Container() {
      return (
        <div>
          <h3>Total Click: {counter}</h3>
          <button onClick={countUp}>Click me</button>
        </div>
      );
    }
    //ReactDOM.render(<Container />, root);
    render();
  </script>
</html>

단점 : 데이터가 바뀔 때마다, 계속해서 리렌더링 함수 render();를 호출 해줘야함.

이유: 위 컴포넌트는 단 한번만 렌더링하고 끝이고, UI를 새로고침해주는 코드가 없기 때문에, 새로 리렌더링 함수를 다른 함수 실행시 매번 같이 실행해줘야 함.


리액트 VS 바닐라자바스크립트 업데이트 차이

자바스크립트는 카운터가 업데이트 될 때, 해당 태그 전체가 업데이트 됨.

  • <span> 태그 전체
    <span>Total Clicks: 1</span>이 업데이트 됨

리액트는 UI에서 바뀐 부분만 업데이트 함.

  • 오직 {counter} 부분만 업데이트 함.
  • <h3> "Total Click:" 등 다른 태그들을 재생성할 필요도 없음.

리액트.js 업데이트 방식

    1. 이전에 렌더링된 컴포넌트 확인
    1. 다음에 렌더링될 컴포넌트 확인
    1. 오로지 바뀐 부분만 찾아서 업데이트 리렌더링 해줌

리액트 장점

  • 굉장히 인터렉티브한 어플리케이션을 만들 수 있음.
  • 여러가지 요소들을 리렌더링하려고 해도 전부 다 새로 생성하지 않음

  1. (best way) useState 변수 선언 + 실행함수 = 자동 업데이트

기존 방법
let counter = 0; 변수에 담기

새로운 방법
let counter = useState(초기값);

👉 콘솔창에 Array배열을 받게됨.
👉 [undefined, f함수] 배열은
[(현재)데이터, 데이터를 바꿀때 사용하는 함수]를 의미.
(=> 위 두 요소들이, 우리가 이전 예제의 counte변수와 countUp()함수의 역할을 대신해주고 있음.)

useState() 방법 예제

function App() {
      const data = React.useState();
      console.log(data);
      return (
        <div>
          <h3>Total Click: {counter}</h3>
          <button>Click me</button>
        </div>
      );
    }
ReactDOM.render(<App />, root);

React.useState() 함수는 초기값을 설정 가능.

const data = React.useState(0);

만약에 데이터값을 사용하고 싶다면? data[0], data[1] 이렇게 접근 가능.

const data = React.useState(999);
const counter = data[0];
const modifier = data[1];

더 좋은 방법 구조분해할당으로 처리

let counter = React.useState(초기값);
=> let [currentValue, modifier] = React.useSatet(초기값)

  <script type="text/babel">
    const root = document.getElementById("root");
    function App() {
      const [counter, modifier] = React.useState(0);
      return (
        <div>
          <h3>Total Click: {counter}</h3>
          <button>Click me</button>
        </div>
      );
    }
    ReactDOM.render(<App />, root);
  </script>

  1. 업데이트 함수 만들기
    ❗ counter 변수값 업데이트 되야하니까 const -> let 으로 변경
let [counter, modifier] = React.useState(0);
const onClick = () => {
        counter = counter + 1;
        console.log(counter);
};
  1. 이벤트리스너 함수 등록
<button onClick={onClick}>Click me</button>
  1. 화면을 리렌더링
  • 업데이트 함수로 리렌더링을 자동으로 발생시킴.
  • 업데이트 함수명은 주로 set+함수명으로 설정함.
const [counter, setCounter] = React.useState(0);
const onClick = () => {
	setCounter(counter + 1);
};

최종 코드

<!DOCTYPE html>
<html>
  <body>
    <div id="root"></div>
    <script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
    <script src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>
    <script src="https://unpkg.com/@babel/[email protected]/babel.min.js"></script>
    <script type="text/babel">
      const root = document.getElementById("root");
      function App() {
        const [counter, setCounter] = React.useState(0);
        const onClick = () => {
          setCounter(counter + 1);
        };
        return (
          <div>
            <h3>Total clicks: {counter}</h3>
            <button onClick={onClick}>Click me</button>
          </div>
        );
      }
      ReactDOM.render(<App />, root);
    </script>
  </body>
</html>


❗setState() 사용법

setState() 함수를 셋팅하는 2가지 방법

  • 1) 직접할당: setState(현재값+1)
  • 2) 함수할당: setState((현재값) => {업데이트 리턴값 & 함수}) 함수
    • (함수의 첫번째 인자는 현재 state 임)

1) 직접할당: setState(현재값+1)

setState(state+1)

const [counter, setCounter] = React.useState();
const onClick = () => {
          setCounter(counter+1);
};
  • 현재 state랑 state업데이트에 관련이 없는 값을 새로운 state로 하고싶은 경우

2) 함수할당: setState((현재값) => {리턴값&규칙}) 함수

setState((state) => (state+1))

const [counter, setCounter] = React.useState(0);
const onClick = () => {
          setCounter((current) => current + 1);
};
  • 현재 state값에 변화를 주어서 새로운 state로 업데이트를 하고 경우
  • 이 함수의 1번째 argument는 현재값이고, 리턴값이 새로운 state가 됨

결론: 2번 함수할당 방식이 현재값 업데이트에는 더 좋음
이유:

  • 현재값을 바탕으로 새로운 값을 계산해 업데이트해주는 2번 방식이 더 안전한 방식이라고 함
  • {함수} 사용으로 current가 확실히 현재값이라는 것을 보장해줌
  • (2)함수할당 방식은 함수내에서 호출 횟수마다 current상태값을 업데이트해주는 것을 보장함.
  • (1)직접할당 방식은 함수내에서 호출 횟수에 상관없이 무조건 1번만 업데이트 해줌.

전체코드

<!DOCTYPE html>
<html>
  <body>
    <div id="root"></div>
    <script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
    <script src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>
    <script src="https://unpkg.com/@babel/[email protected]/babel.min.js"></script>
    <script type="text/babel">
      const root = document.getElementById("root");
      function App() {
        const [counter, setCounter] = React.useState(0);
        const onClick = () => {
          setCounter((current) => current + 1);
        };
        return (
          <div>
            <h3>Total clicks: {counter}</h3>
            <button onClick={onClick}>Click me</button>
          </div>
        );
      }
      ReactDOM.render(<App />, root);
    </script>
  </body>
</html>

보충 설명 (setState())
1.직접할당 2.함수할당 결과값 차이

예제
아래와 같이 코드를 넣고 실행해보면,

  • 1번 직접할당: 클릭당 리턴값 : 1,2,3,4,5
  • 2번 함수할당: 클릭당 리턴값 : 5,10,15,20

1번 직접할당: 값으로 여러번 호출한 결과값: 1,2,3,4,5
function onClick() {
setCounter(counter + 1);
setCounter(counter + 1);
setCounter(counter + 1);
setCounter(counter + 1);
setCounter(counter + 1);
}

2번 함수할당: 함수로 여러번 호출한 결과값 5,10,15,20

function onClick() {
setCounter(current => current+ 1);
setCounter(current => current+ 1);
setCounter(current => current+ 1);
setCounter(current => current+ 1);
setCounter(current => current+ 1);
}

결과

  • 1번으로 돌렸을 경우, setCounter를 몇 번을 호출해도 한 번만 실행됨. (counter가 1만 증가)
  • 2번으로 돌렸을 경우, setCounter가 호출된 횟수 만큼 counter가 5씩 증가됨.






<참고>
https://nomadcoders.co/react-for-beginners
https://ko.reactjs.org/tutorial/tutorial.html

<더 읽어보기>
SyntheticEvent, Event Pooling, event.persist():
https://ko.reactjs.org/docs/events.html
https://ko.reactjs.org/docs/handling-events.html
https://medium.com/react-native-seoul/react-%EB%A6%AC%EC%95%A1%ED%8A%B8%EB%A5%BC-%EC%B2%98%EC%9D%8C%EB%B6%80%ED%84%B0-%EB%B0%B0%EC%9B%8C%EB%B3%B4%EC%9E%90-06-%ED%95%A9%EC%84%B1-%EC%9D%B4%EB%B2%A4%ED%8A%B8%EC%99%80-event-pooling-6b4a0801c9b9
https://abangpa1ace.tistory.com/129
https://frontcode.tistory.com/60

좋은 웹페이지 즐겨찾기