import React, { useState } from "react";
export default function App() {
const [number, setNumber] = useState(1);
const add = () => setNumber(number + 1);
const subtract = () => setNumber(number - 1);
const multiplyBy2 = () => setNumber( number * 2);
const multiplyBy2AndAddBy1 = () => {
multiplyBy2();
add();
};
return (
<div>
<h1>Number : {number}</h1>
<div>
<button onClick={add}>+ 1</button>
<button onClick={subtract}>- 1</button>
<button onClick={multiplyBy2}>*2</button>
<button onClick={multiplyBy2AndAddBy1}>*2 + 1</button>
</div>
</div>
);
}
위의 코드는 현재 버튼의 값을 보여주는 Number와 4개의 버튼으로 이루어져 있다.
기본 값은 1이고, 버튼을 누르면 버튼의 숫자만큼 커지거나 작아지는 방식이다.
multipleBy2AndAddBy1 함수를 보자.
const multiplyBy2AndAddBy1 = () => {
multiplyBy2(); // number에 x2를 해주고
add(); // 곱한 값에 +1을 해준다.
};
그리고 결과 화면을 보자.
기본 값은 1, 차례로 [+1], [*2], [*2 + 1] 버튼을 눌러주었다.
나머지는 정상적으로 작동을 하지만 [*2 + 1] 버튼은 값이 +1만 되는 것을 볼 수 있다.
만약, setState가 동기적으로 실행이 됐다면 multiplyBy2()함수가 실행되고 난 후, add()함수가 실행이 됐을 것이다.
하지만 multiplyBy2()는 적용되지 않고 add()함수만 적용된 결과가 보여지고 있다.
이유는 setState가 비동기로 이루어지기 때문이다.
state 업데이트는 병합된다.
setState를 호출할 때 react는 제공한 객체를 현재 state로 병합한다.
const add = () => setNumber(number + 1);
const subtract = () => setNumber(number - 1);
const multiplyBy2 = () => setNumber( number * 2);
const multiplyBy2AndAddBy1 = () => {
multiplyBy2();
add();
};
Object.assign({ number, number: number * 2, number : number + 1 });
이러한 문제를 해결하기 위해서는 숫자를 바로 넘기지 않고 setState에게 함수를 넘겨줘야 한다.
현재의 state(코드 상에서는 number)를 인자로 넘겨주면 된다.
import React, { useState } from "react";
export default function App() {
const [number, setNumber] = useState(1);
const add = () => setNumber((number) => number + 1);
const subtract = () => setNumber((number) => number - 1);
const multiplyBy2 = () => setNumber((number) => number * 2);
const multiplyBy2AndAddBy1 = () => {
multiplyBy2();
add();
};
return (
<div>
<h1>Number : {number}</h1>
<div>
<button onClick={add}>+ 1</button>
<button onClick={subtract}>- 1</button>
<button onClick={multiplyBy2}>*2</button>
<button onClick={multiplyBy2AndAddBy1}>*2 + 1</button>
</div>
</div>
);
}
이렇게 작성하면 정상적으로 multiplyBy2()함수가 정상적으로 적용되는 것을 볼 수 있다.
위처럼 변경한다고 해서 setState가 동기적으로 실행되는 것은 아니다.
하지만, 함수를 인자로 넘겨주면 다음 병합시에 업데이트 된 number가 인자로 들어가도록 동작하게 되므로 위와 같은 문제를 해결할 수 있다.