state 변경함수 사용할 때 주의점 : async

Steve·2021년 6월 16일
0

동기처리 : 순차적으로 일을 스스로 끝내는 방식
비동기 처리 : 해야 할 일을 위임하고 기다리는 방식

JS는 일반적으로 sync하게 처리됨(동기식)
: 코드 적은 순서대로 윗줄부터 실행

하지만 js는 async하게 코드실행 가능(비동기처리 방식)

ajax, 이벤트리스터, setTimeout 이런 함수들이 있습니다.

이런 함수들은 처리시간이 오래걸림.
그래서 ajax요청하는 코드들은 순차적 실행이 안되고 다른게 완료되면 실행됩니다.

예를들어

console.log(1) // 1번째 실행
axios로 get요청하고나서 console.log(2) 실행해주셈~ // 마지막으로 실행
console.log(3) // 2번째 실행

2을 출력하는 코드가 async처리를 지원하는 코드라서 맨 마지막에 실행합니다.
2을 출력할 때 오래걸리면 잠깐 보류했다가 다른코드를 먼저 실행시킨다는 소리입니다.
심지어 ajax요청이 0.00초 걸려서 맨 마지막 실행됨.
물리적으로 잠깐 처리가 보류돼서 그렇습니다

우리가 리액트로 state어떻게 만드는지 기억하나?
function App() {
let [name, setName] = useState('kim')
}

setName을 이용해서 state를 자유롭게 변경 가능합니다.
setName('park'); 이런식으로.
문제는 setName()같은 state변경함수들은 전부 async로 처리됩니다.
setName()이 오래걸리면 이걸 제끼고 다른거부터 실행한다는 겁니다.

예시 : 버튼을 누르면 2개 기능을 순차적으로 실행하고 싶다면?

function App(){
  let [count, setCount] = useState(0);
  let [age, setAge] = useState(20);

  return (
    <div>
      <div>안녕하십니까 전 {age}살 입니다</div>
      <button onClick={()=>{
        setCount(count++); // 이 코드는 오래걸림. 그래서 일단 제껴둠
        if(count < 3){ // 윗줄 setCount 제껴두고 이거부터 실행
          setAge(age++); // count는 아직 2라서 age++이 동작함
        }
      }}>누르면한살먹기</button>
    </div>
  )
}

위와 같은 상황이 발생하는 이유는
setCount()가 async 함수라서 그렇습니다.
async함수는 오래걸리면 제껴두고 다음줄 코드부터 실행.

처음 의도대로 count가 3이되면 더이상 나이를 age++실행을 막으려면?

function App(){
  let [count, setCount] = useState(0);
  let [age, setAge] = useState(20);
	
  useEffect( () => { //컴포넌트가 랜더링, 재랜더링 될 때 실행되는 함수
    
  }, [count] )
  return (
    <div>
      <div>안녕하십니까 전 {age}</div>
      <button onClick={()=>{
        setCount(count++); // 이 코드는 오래걸림. 그래서 일단 제껴둠
        if(count < 3){ // 윗줄 setCount 제껴두고 이거부터 실행
          setAge(age++); // count는 아직 2라서 age++이 동작함
        }
      }}>누르면한살먹기</button>
    </div>
  )
}

근데 문제는 useEffect 저렇게 써도 처음 페이지 로드될 때도 한번 실행이 되기 때문에 의도치 않은 버그가 발생할 수 있다.

그렇기 때문에 첫페이지 로드할때는 useEffect는 실행이 안되게 하는 조건을 걸어주면 된다.

function App(){
  let [count, setCount] = useState(0);
  let [age, setAge] = useState(20);
	
  useEffect( () => { 
    if(count != 0 && count < 3){ // 첫번째 랜더링이 count===0일땐 실행안되게 처리함.
      setAge(age++); // count는 아직 2라서 age++이 동작함
    }
  }, [count] ) // count에 변화가 있을 경우에만 useEffect 실행하게해주셈
  return (
    <div>
      <div>안녕하십니까 전 {age}</div>
      <button onClick={()=>{
        setCount(count++); // 버튼 클릭할때마다 count 1증가
      }}>누르면한살먹기</button>
    </div>
  )
}
profile
Front-Dev

0개의 댓글