[React] State가 변경 되었는데, 재 렌더링이 안된다면?

useState를 잘못 사용하여 재 렌더링이 되지 않는 상황을 마주쳤습니다.

기본적인 부분이라고 생각하지만, 저와 같은 실수를 하시는 분이 있으실 수 있어 블로그 포스팅을 해봅니다!

❓React 요소가 재 렌더링 되는 시점?

기본적으로 React의 요소가 재 렌더링 되는 경우는 다음과 같습니다.

  1. State가 변경되었을 때
  2. Props가 변경 되었을 때
  3. 부모 컴포넌트가 재 렌더링 될 때
  4. 컨텍스트(useContext 훅을 사용하여)에 의존하고 있는 경우 컨텍스트 값이 변경될 때

네 가지 상황에서 재 렌더링이 실행됩니다. 그런데 제가 마주친 상황은 State가 변경되었음에도, 재 렌더링이 되지 않는 상황이었습니다.

//...
const [files, setFiles] = useState([]);
const inputForm = useForm();
const inputFiles = inputForm.watch("files")

useEffect(()=>{
	if(inputFiles && inputFiles.length > 0){
		setFiles((files)=>{
			files.push(inputElement)
			return files
		})
	}
},[inputElement])

return //...

위 상황은 React-Hook-Form 을 사용하여, file을 받아오는 input을 만들고, 그 input을 받아올 때, file state에 담는 코드입니다.

하지만 파일을 담을 때 재 렌더링이 일어날 줄 알았지만, 예상 외로 재 렌더링은 발생하지 않았습니다.

setFiles를 실행하였음에도 왜 재 렌더링이 일어나지 않은 것일까요?

❗State가 변경되었음에도, 재 렌더링 되지 않을 땐 상태의 불변성을 확인하자.

위 상황은 React가 State의 상태 변화를 감지하지 못한 상황입니다.

이 코드는 잘못되었는데요,

setFiles((files)=>{
	files.push(inputElement)
	return files
})

files에 데이터를 push하고, 그 파일을 그대로 return해주는 모습입니다.

이는 상태 변화를 감지하지 못하는 상황인데요, 이는 참조 동등성(Reference Equality)과 관련이 있습니다.

React는 컴포넌트의 상태가 변경하는지 확인할 때, 참조가 변경되는지를 확인합니다.

const arr = [1,2,3]
arr.push(4)
console.log(arr) // [1,2,3,4]
// 기존 arr에 4를 집어 넣음.

arr가 변경되었음에도, 기존 arr에 [1,2,3,4]라는 값이 생기는 것이지, 참조가 달라지진 않습니다.

const arr = [1,2,3]
[...arr,4]
console.log(arr) // [1,2,3]
// 새로운 배열을 만들어서 기존 arr와는 다른 arr에 4가 놓이게 됨.

스프레드 문법을 활용하여 새로운 arr를 만들고, 그 곳에 새로운 값은 4를 넣어주는 모습입니다. 이런 식으로 만들어야 참조가 달라지기 때문에, React에서 상태 변화로 감지할 수 있는 것입니다.

그렇다면 기존 코드를 이렇게 바꿔야겠네요.

setFiles((files)=>{
	const newFiles = [...files, inputElement]
	return newFiles
})

이제 정상적으로 작동하는 코드를 만날 수 있었습니다!

 

이 부분은 사실 기본적인 부분인 것 같음에도, 제대로 익히지 못하고 있었다는 것에 아쉬운 마음이 있었습니다. 아무튼 기본적인 리액트의 동작 원리에 대해서 공부해야할 필요성을 느낀 부분이었네요!