반응형

🚀

리액트에서 setState 후 변경된 state값을 사용하는 경우가 종종 있으며, Callback 함수를 사용하여 해결할 수 있습니다.

 

🚩 setState를 한 뒤 state를 사용하는 경우

📋 코드

import React, { Component } from "react";
import styled from "styled-components";
import "./App.css";

const Wrapper = styled.div`
  display: flex;
  margin: 20px;
`;

const Print = styled.div`
  border-radius: 5px;
  border: 1px solid #6c757d;
  width: 80px;
  height: 30px;
  font-size: 20px;
  text-align: center;
`;

const Button = styled.button`
  background-color: #6c757d;
  border-radius: 5px;
  border: 0px;
  color: white;
  width: 80px;
  height: 30px;
  margin-left: 10px;
  &:hover {
    background-color: #5a6268;
  }
`;

class App extends Component {
  constructor(props) {
    super(props);
    this.state = { counter: 0 };
  }

  onClick = () => {
    this.setState({ counter: this.state.counter + 1 });
    console.log(this.state.counter);
  };

  render() {
    return (
      <Wrapper>
        <Print>{this.state.counter}</Print>
        <Button onClick={this.onClick}>+1</Button>
      </Wrapper>
    );
  }
}

export default App;

버튼을 누르면 state의 counter 값이 +1씩 증가하게 하는 예제입니다.

  onClick = () => {
    this.setState({ counter: this.state.counter + 1 });
    console.log(this.state.counter);
  };

onClick 함수에서 setState로 state를 변경해주고 this.state.counter 출력 시 결과는 아래와 같습니다.

1이 출력되기를 기대했지만 예상과는 다르게 바뀌기 이전 값이 '0'이 출력되었습니다.

 

🤔 Why?

setState 함수는 비동기 함수이기 때문에 이벤트 핸들러 함수에서 바로 값을 갱신하는 것이 아닌 이벤트 핸들러 함수 종료 후 state값이 갱신됩니다.

 

✔️ 클래스형 컴포넌트의 setState Callback 사용법

<setState 함수의 정의>

setState<K extends keyof S>(
  state: ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null),
  callback?: () => void
): void;

setState함수는 2개의 인자를 받는데 첫 번째 인자는 변경할 state를 전달하며, 두 번째 인자는 state가 변경된 후 실행되는 callback 함수를 전달합니다.

 

📋 코드

import React, { Component } from "react";
import styled from "styled-components";
import "./App.css";

const Wrapper = styled.div`
  display: flex;
  margin: 20px;
`;

const Print = styled.div`
  border-radius: 5px;
  border: 1px solid #6c757d;
  width: 80px;
  height: 30px;
  font-size: 20px;
  text-align: center;
`;

const Button = styled.button`
  background-color: #6c757d;
  border-radius: 5px;
  border: 0px;
  color: white;
  width: 80px;
  height: 30px;
  margin-left: 10px;
  &:hover {
    background-color: #5a6268;
  }
`;

class App extends Component {
  constructor(props) {
    super(props);
    this.state = { counter: 0 };
  }

  onClick = () => {
    this.setState({ counter: this.state.counter + 1 }, () => {
      console.log(this.state.counter);
    });
  };

  render() {
    return (
      <Wrapper>
        <Print>{this.state.counter}</Print>
        <Button onClick={this.onClick}>+1</Button>
      </Wrapper>
    );
  }
}

export default App;

// function App() {
//   return (
//     <Wrapper>
//       <Print></Print>
//       <Button></Button>
//     </Wrapper>
//   );
// }

  onClick = () => {
    this.setState({ counter: this.state.counter + 1 }, () => {
      console.log(this.state.counter);
    });
  };

따라서 위와 같이 state를 변경하고 callback함수로 변경된 state를 사용할 수 있게 됩니다.

 

 

✔️ 함수형 컴포넌트의 setState Callback 사용법

리액트 16.8 이전 버전에서는 함수형 컴포넌트에서 상태를 관리할 수 없었는데, 리액트 16.8 버전에서 Hooks라는 기능이 도입되면서 useState라는 함수를 사용하여 함수형 컴포넌트에서도 상태를 관리할 수 있게 되었습니다. 

그러나 useState 함수의 경우 두 번째 인수가 존재하지 않기 때문에 userEffect를 사용하여 변경된 state를 사용해보겠습니다.

📋 코드

import React, { Component, useState, useEffect } from "react";
import styled from "styled-components";
import "./App.css";

const Wrapper = styled.div`
  display: flex;
  margin: 20px;
`;

const Print = styled.div`
  border-radius: 5px;
  border: 1px solid #6c757d;
  width: 80px;
  height: 30px;
  font-size: 20px;
  text-align: center;
`;

const Button = styled.button`
  background-color: #6c757d;
  border-radius: 5px;
  border: 0px;
  color: white;
  width: 80px;
  height: 30px;
  margin-left: 10px;
  &:hover {
    background-color: #5a6268;
  }
`;

function App() {
  const [counter, setCounter] = useState(0);

  const onClick = () => {
    setCounter(counter + 1);
  };

  useEffect(() => {
    console.log(counter);
  }, [counter]);

  return (
    <Wrapper>
      <Print>{counter}</Print>
      <Button onClick={onClick}>+1</Button>
    </Wrapper>
  );
}

export default App;

useEffrct에서 두 번째 인자로 배열에 state를 넣어서 해당 state가 변경(업데이트)되면 useEffect 함수가 실행되도록 하였습니다.

 

 

🔎 useEffect 추가 설명

  useEffect(() => {
    console.log("마운트 될 때만 실행");
  }, []);

  useEffect(() => {
    console.log("렌더링 될 때마다 실행");
  });

  useEffect(() => {
    console.log("counter가 업데이트 될 때마다 실행");
  }, [counter]);

 

 

 

반응형

+ Recent posts