react로 개인 프로젝트를 하는 와중에 api를 호출하는 부분이 들어갔는데, 컴포넌트가 두 번씩 렌더링 되면서 api도 두번씩 호출되는 상황이 발생하였다 ㅠㅠ (핵심적인 부분만 담기 위한 코드를 별도 작성하였다)
import { useEffect, useState } from "react"
export default function Todo() {
const [todoList, setTodoList] = useState([])
useEffect(() => {
console.log('api 호출')
setTodoList([
{
name: '설거지'
}
])
}, [])
return (
<div>
<h2>Todo API 호출테스트</h2>
{
todoList.map((todo, todoIndex) => <p key={todoIndex}>{todo.name}</p>)
}
</div>
)
}
일단 google에 react 18 render twice를 검색했고 관련한 여러가지 블로그 글이나 스택오버 플로우 게시글들을 확인해보았다. 그러나 하나같이 <React.StrictMode>를 주석처리하는 얄팍한 방식을 쓰고 있었다 😭😭😭
React 18에서 StrictMode가 사용되는 것은 컴포넌트가 빠르게 mount, unmount될때 문제가 발생할 수 있는 부분들 (주로 애니메이션 이벤트 등 DOM을 직접조작하는 이벤트)을 미리 검증하기 위하여 아주 빠르게 mount -> unmount -> mount 싸이클을 돌린다는 사실을 알게되었다.
그래서 mount가 완료가 되었다는 사실을 didMount라는 state에 저장하고 이를 토대로 마운트가 완료된 경우에 api를 호출 하는 방식으로 변경하였다.
import { useEffect, useState } from "react"
import { Link } from "react-router-dom"
let mountCount = 1
export default function Todo() {
const [todoList, setTodoList] = useState([])
const [didMount, setDidMount] = useState(false)
useEffect(() => {
console.log('mount: ', mountCount)
mountCount++
setDidMount(true)
return () => {
console.log('unmount')
}
}, [])
useEffect(() => {
console.log('didMount: ', didMount)
if (didMount) {
console.log('api 호출')
const fetchData = [
{
name: '설거지'
}
]
setTodoList(fetchData)
}
}, [didMount])
return (
<div>
<h2>Todo API 호출테스트</h2>
{
todoList.map((todo, todoIndex) => <p key={todoIndex}>{todo.name}</p>)
}
<Link to='/home'>Home</Link>
</div>
)
}
React.StrictMode로 인해 mount, unmout가 발생한 이후에 최종적으로 mount가 실행되는 것을 볼 수 있고 mount이후에 api 호출이 될 수 있도록 didMount값을 true로 변경시켜 주었다.
최초의 mount (mount: 1)시에 didMount값을 true로 변경하더라도 변경을 감지하지 업데이트 하지않고 최종적으로 mount (mount: 2) 될때만 state변경을 감지하여 useEffet(() => {}, [didMount])
가 업데이트 되는 것을 볼 수 있었다.
Solving the React 18 Double Render problem - https://www.youtube.com/watch?v=VUg7olsnusg
api 호출의 경우 unmount 될때 취소하는 방식이 더 나은 방식으로 보여서 포스팅을 추가하였다.
React 18 strict mode에서 double mount로 인한 axios 중복 호출 막기 두번째 방법! (with AbortController)
https://velog.io/@sonaky47/React-18-strict-mode%EC%97%90%EC%84%9C-double-mount%EB%A1%9C-%EC%9D%B8%ED%95%9C-axios-%EC%A4%91%EB%B3%B5-%ED%98%B8%EC%B6%9C-%EB%A7%89%EA%B8%B0-%EB%91%90%EB%B2%88%EC%A7%B8-%EB%B0%A9%EB%B2%95-AbortController