[React] 변경함수 사용할 때 주의점 : async

qwe8851·2022년 10월 19일
0

💎 React

목록 보기
28/37

🤔 자바스크립트의 sync/acync 관련 상식


sync(동기)

js는 일반적인 코드를 작성하면 synchronous하게 처리됨.
뭔소리냐면 코드를 적은 순서대로 윗줄부터 차례로 코드가 실행된다는 뜻임

예를 들어

console.log(1+1)
console.log(1+2)
console.log(1+3)

이런 코드는 위에서 부터 순서대로 실행되므로
콘솔창에 2, 3, 4가 순서대로 출력됨


async(비동기)

근데 ajax, 이벤트리스터, setTimeout같은 함수를 쓸 때 asynchronous 처리가 됨

이런 함수들의 특징은 처리시간이 오래걸림
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이 출려됨
물리적으로 잠깐 처리가 보류되어서 그럼

js라는 언어의 특징이자 장점임




🤔 리액트의 setState함수 특징


function App(){
  let [name, setName] = useState('kim');
}

리액트로 일반적인 state함수를 만들어 봤음.

여기서 setName('park')을 쓰면 name이 park으로 변경되겠죠?
근데 여기서 setName()같은 state변경함수들도 모두 asynchronous(비동기적)으로 처리됨

그니까 setName()이 오래걸리면 이걸 제쳐두고 밑에 있는 다른 코드들부터 실행된다는 거임

그래서 뭔가 예상치 못한 문제가 생길 수도 있음.




🤔 비동기 처리로 인한 예상치 못한 문제들?


예제 1. 버튼 누를때마다 나이 한 살 더 먹기

function App(){
  let [count, setCount] = useState(0);
  let [age, setAge] = useState(20);
  
  return(
    <div>
      <div>안녕하세요 저는 {age}</div>
      <button>누르면 한 살 먹기</button>
    </div>
  )
}

버튼을 누를때마다
1. count를 +1(버튼누른횟수 기록용)
2. age +1
3. 근데 count가 3이상이라면 더이상 age+1을 하지 않기

버튼 3번 이상 누르면 (count가 3이상이면) 나이를 그만 더하는 기능임. 그니까 22에서 멈춰야함



예제 답안

<button onClick={()=>{

  setCount(count+1);
  if ( count < 3 ) {
    setAge(age+1);
  }
         
}}>누르면 한 살 먹기</button> 

그래서 이렇게 코드짯는데 뭔가 이상함

age가 22가 되면 더 이상 증가하지 않고 멈춰야 하는데 23까지 증가함.

count가 1일 때 age+1
count가 2일 때 age+1
count가 3일 때 age+1을 하지마! 라고 했는데
지금 count가 3일 때도 age+1을 해주고 있음.


이 문제의 원인은 setCount()가 async함수라서 그럼.

state변경함수는 async하게 처리되는 함수이기 때문에 완료되기까지 시간이 오래걸려 제쳐두고 다음 코드를 실행해줌.

그래서 이 코드를 해석해보자면
1. 버튼을 3번째 누르면 setCount(count+1)을 실행해서 count를 3으로 만들어줌.
2. 근데 count를 3으로 만드는건 오래걸리니까 제쳐두고 if(count>3){}먼저 실행함
3. 이 때 count는 아직 2라서 if문 안의 setAge(age+1)이 동작된 것


그래서 저렇게 state1을 변경하고 나서 state2를 변경하는 코드를 작성할 때 문제가 생김ㅜㅜ

이걸 정확히 sync스럽, 순차적으로 실행하고 싶으면 useEffect를 쓰면 된다.

state가 변경될 때 useEffect를 실행해달라고 하면 될 듯?



최종 예제 답안

useEffet(()=>{
  
}, [count])

useEffet는 컴포넌트가 렌더링/재랜더링될 때 실행되는 함수임.
근데 뒤에 dependency([]) 안에 state를 넣으면
state가 변경되면 안에 코드를 실행해주세요~ 라고 코드짤 수 있음.

그래서 이걸 써서
1. count라는 state가 변경되고 나서
2. age+1 해주삼
이런식으로 순차적으로 실행되는 코드를 짤 수 있을 듯


  1. count라는 state가 변경되면
<button onClick={()=>{

}}>누르면 한 살 먹기</button> 

  1. age+1 해주삼
<button onClick={()=>{
  if ( count < 3 ) {
    setAge(age+1)
  }
}}>누르면 한 살 먹기</button> 

이렇게 하면 끝

그럼 useEffect는 count라는 state가 변경되고 나서 안에 있는 코드를 실행해 줌
그래서 if문으로 count라는 state를 의도대로 측정해볼 수 있음


근데 또 문제가 있음..ㅋㅋ
useEffect는 처음 페이지 로드될 때 한 번 실행되기 때문에 의도치 않음 버그가 생길 수 있음

그래서 처음 페이지 로드 시 useEffect실행을 막는 코드를 검색해서 적용해도 되고,
count라는 state를 또 활용해도 될 듯



진짜 최종 예시답안

useEffect()=>{
  if(count !=0&& count<3) {
    setAge(age+1)
  }
}, [count])

count가 0일때(페이지 처음 로드 시)는 내부코드를 동작시키지 말아주세요~ 라고 코드짰음

이제 버튼을 누르면 22살까지만 잘 동작함.



일케하면 문제해결이긴 하다만... ㅎ

  • count와 age를 동시에 한 곳의 state에 array/object자료형으로 집어넣거나
  • 하나는 굳이 state로 만들지 않고 일반 변수로 만드는 것도 괜찮을 듯? 변경 시 html자동랜더링이 필요한 변수들은 state로 만들라고 햇으니..

이런 문제들은 다음 포스트에서 다뤄보자!

profile
FrontEnd Developer with React, TypeScript

0개의 댓글