//index.d.ts
/**
* Returns a stateful value, and a function to update it.
*
* @version 16.8.0
* @see https://reactjs.org/docs/hooks-reference.html#usestate
*/
function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
//useState함수는 초기상태S(혹은 초기상태 S를 설정하는 콜백함수)를 전달하면 배열형태로 상태S와 S의 상태를 설정하는 함수를 배열형태로 반환한다.
setState함수를 사용하면 리액트가 컴포넌트를 다시 호출, 변경된 state가 기억되고 DOM에서 업데이트 된다.(virtualDOM기능으로 필요부분만)
//사용시
import React, { useState } from "react";
export function Counter() {
const [count, setCount]=useState(0);
return (
<div className='counter'>
<span className="number">{count}</span>
<button className="button" onClick={()=>setCount(count+1)}>Add +</button>
</div>
);
}
useEffect는(정확히는 setState) 기본적으로 비동기적으로 동작한다.
그 이유는
페이지를 구성하는 수많은 setState가 모두 동기적으로 작동한다면 하나의 state변화에 전체 화면이 리렌더링 되고, 성능저하가 발생할 수 있다.
이를 해결하기 위해서 React는 setState가 연속 호출됙면 배치처리(batch Update)를 통해 한번에 랜더링하게 된다.
->많은 setState를 연속으로 사용해도 배치처리로 인해 렌더링은 한번만 된다.
여기서 배치처리(Batch Update)란
React가 여러개의 state 업데이트를 한번에 리렌더링하기 위해 묶는것을 의미한다.
- setState값의 업데이트는 16ms단위로 이루어진다.
따라서 16ms 내 변경된 state값은 한번에 업데이트된다.const handleNumber = () => { setNum(num + 1); setNum(num + 1); setNum(num + 1); };
이렇게 작성하여도 실제로 setNum은 한번만 발생하게 된다.
이러한 비동기적 문제를 해결하기 위해서는
setState의 인자로 콜백함수를 집어넣는 것이다.
setNum((prev)=>prev+1);
형태로 사용하게 된다면 동기적으로 처리하게 되어 위와같은 상황에 setNum함수가 3번 실행된다.
또, useState 안에 들어가는 기본값이 무거운 작업일때, useState(()=>heavyworks())
처럼 콜백함수의 형태로 반환할 수 있다. 처음 렌더링시에만 콜백을 실행해서 초기값을 만들고, 그 이후에는 콜백하지 않기 때문에 오래걸리는 작업일 때 사용하면 좋다. 단, 콜백리턴까지 React가 렌더링을 하지 않고 기다리므로 첫 렌더링이 늦어질 수 있다.