자바스크립트의 sync / async 관련 상식
자바스크립트는 일반적인 코드를 작성하면 synchronous(동기)하게 처리 됩니다.
코드적은 순서대로 윗줄부터 차례로 코드가 실행된다는 뜻입니다.
자바스크립트는 이상한 함수들을 사용하면 asychronous(비동기적)하게 코드실행이 가능합니다.
ajax, 이벤트리스너, setTimeout 이런 함수들을 쓸 때 그런 현상이 일어납니다.
이런 함수들은 처리시간이 오래걸립니다. ajax를 예로 들면 인터넷 상황이 안좋으면 코드실행이 오래걸릴 수 있습니다.
그래서 ajax 요청하는 코드들은 순차적으로 실행되지 않고 완료되면 실행됩니다.
예를 들어보면
console.log(1+1)
axios로 get요청하고나서 console.log(1+2) 실행해주는 코드
console.log(1+3)
이런 코드는 2,4 가 바로 출력되고 그 다음에 3이 출력됩니다.
3을 출력하는 코드가 asynchronous 처리를 지원하는 코드라 그렇습니다.
3을 출력할 때 오래걸리면 완료될 때 까지 잠깐 보류했다가 다른 코드를 먼저 실행시킨다는 소리입니다.
심지어 ajax 요청이 0.00초 걸려도 2,4가 먼저 그다음 3이 출력됩니다. (물리적으로 잠깐 처리가 보류되어서)
자바스크립트라는 언어의 특징이자 장점이라고 볼 수 있습니다.
리액트의 setState 함수 특징
리액트로 state 만들 땐 이렇게 합니다.
function App(){
let [name, setName] = useState('kim')
}
그리고 이제 setName을 사용하면 name이라는 state를 자유롭게 변경가능합니다.
setName('park')이런 식으로 하면 변경된다는 겁니다.
근데 문제는 setName() 같은 state 변경함수들은 전부 asynchronous(비동기적)으로 처리됩니다.
그니까 setName()이 오래걸리면 이거 제껴두고 다른 밑에 있는 코드들부터 실행한다는 겁니다.
그래서뭔가 예상치 못한 문제가 생길 수 있습니다.
예제. 버튼을 누르면 2개 기능을 순차적으로 실행
- count라는 state를 +1
- age라는 state로 +1
- 근데 count가 3 이상이면 더 이상 age라는 state를 1 더하지 말라는 코드( 22살에서 멈춰야한다)
function App(){
let [count, setCount] = useState(0);
let [age, setAge] = useState(20);
return (
<div>
<div>안녕하십니까 전 {age}</div>
<button>누르면한살먹기</button>
</div>
)
}
아래와 같이 코드를 짯습니다.
<button onClick={()=>{
setCount(count+1);
if ( count < 3 ) {
setAge(age+1);
}
}}>누르면한살먹기</button>
하지만 코드를 실행해보면 23까지 증가합니다.
count가 3일때도 age+1을 해주었습니다. 왜그럴까요?
이유는 async라는 특징 때문에 그렇습니다.
state 변경함수는 async 하게 처리되는 함수기 때문에 완료되기까지 시간이 오래걸리면 제쳐두고 다음 코드를 실행해줍니다. 그래서 코드를 해석해보면
- 버튼을 세번째 누르면 setCount(count+1); 이걸 실행해서 count를 3을 만들어줍니다.
- 근데 count를 3으로 만드는건 오래걸리니까 제쳐두고 if( count>3) {} 이걸 실행합니다.
- 이 때 count는 아직 2라서 if 문 안의 setAge(age+1)이 잘 동작하고 있는 겁니다.
그래서 저렇게 state1 변경하고나서 state2 변경하는 코드를 작성할 땐 가끔 문제가 생깁니다.
이걸 정확히 sync스럽게, 순차적으로 실행하고 싶을 때 해결책은 useEffect 입니다.
useEffect(()=>{
if(count<3&&count!=0)
{
console.log("if");
setAge(age+1);
}
},[count])
useEffect는 컴포넌트가 렌더링/재렌더링될 때 실행되는 함수입니다.
뒤에다가 []대괄호안에 state를 집어넣으면 state가 변경되면 이 코드 실행해줍니다.
조건으로는 count!=0을 추가해주었는데 이유는 페이지가 처음 로딩될때 증가하는걸 방지하기 위해서입니다.
확인해보면 잘 동작합니다.
'프론트엔드 > react' 카테고리의 다른 글
React - fetch(), CRUD(POST, DELETE), useRef (1) | 2023.09.04 |
---|---|
Rest API , 리액트에서 REST API 구축 (1) | 2023.09.04 |
React - 성능개선(useTransition, useDeferredValue) (0) | 2023.08.07 |
React - 성능개선(memo, useMemo) (0) | 2023.08.07 |
React - 성능개선(개발자도구 & lazy import) (0) | 2023.08.07 |