프론트 개발을 하면서 가장 큰 장애물은 비동기 이슈였습니다.
api통신을 해서 data를 받아오고 이를 보여줘야 하는데 axios는 비동기로 동작하기 때문에 렌더링이 먼저되는 상황이 발생하면서 key error 같은 에러가 발생했습니다. 이를 해결하기 위해 loading이라는 state를 사용했습니다. loading의 값을 처음 랜더링 될 때 true로 초기화를 합니다. loading이 true일 때는 loading 페이지를 보여주고 api통신으로 데이터를 받아 온 후 loading 값을 false로 바꿔 우리가 의도한 화면을 보여주었습니다. 다음은 loading을 적용한 예시입니다.
useEffect(() => {
axios.get(`${BASE_URL}quiz/${title}/${currentChapter}/all`, {
headers: {
Authorization: TOKEN,
},
})
.then((res) => {
console.log(res.data);
setQuizs(res.data.results)
setLoading(false) // data를 모두 받으면 laoding을 false로!!
});
}, []);
if (isLoading) {
return <div>Loading...</div>;
} // 로딩 페이지
return (
''' 이하 생략 ''' (진짜로 보여 주고자 하는 페이지)
)
useState로 정의한 변수들은 setState할 때 마찬가지로 비동기로 처리가 된다. 왜냐하면 컴포넌트안에는 다양한 state가 있는데 이 state 값이 바뀔 때마다 리렌더링 한다면 비효율적이기 때문입니다. 때문에 리액트는 성능의 향상을 위해 setState가 연속 호출되면 배치 처리를 하여 한 번에 랜더링합니다. 즉 동일한 key에 대해 이전의 값을 계속 덮어 쓰기 때문에, 결국 마지막 명령어만 수행되는 셈입니다.
(출처: https://garve32.tistory.com/m/39)
해결 방법은 두 가지 입니다.
1. useEffect 의존성 배열 사용
2. setState의 인자로 함수를 집어 넣기
//이전 코드
const onClick = () => {
setCount(count+1);
console.log('click');
setCount(count+1);
console.log('click');
}
//함수형 업데이트 코드
const onClick = () => {
setCount(count => count+1);
console.log('click');
setCount(count => count+1);
console.log('click');
}