리액트에서 가장 자주 보는 오류 메시지이다. 이 오류는 값이 정의되지 않아 읽을 수 없을 때 발생한다.
Uncaught TypeError: Cannot read properties of undefined (reading 'classList')
여기서 알아야할 사실은 state가 비동기적이며 처음 렌더링(마운팅)하기도 전에 동작한다는 것이다. 이 때의 state는 정의되지 않았기 때문에 당연히 undefined다.
때문에 값을 읽을 수 없다는 에러가 출력되는 것이다.
해결 방법
1. State에게 들어올 값의 타입을 미리 알려주자.
State에 미리 값의 타입을 알려주면 undefined를 방지할 수 있다. 그러면 state는 "음, 배열이 들어오겠네? 그냥 아직 데이터가 들어오지 않았을 뿐이군?" 하면서 에러를 뿜어내지 않는다.
function Component() {
// useState 괄호 안이 비어있는 건 비추
const [date, setData] = useState();
// useState에 미리 값의 타입을 알려주자
const [date, setData] = useState([]);
// 혹은
const [date, setData] = useState({});
// 또는
const [date, setData] = useState("");
// 타입을 모르겠다면
const [date, setData] = useState(null);
return (
...
)
}
📌 Case 1. 컴포넌트에서 값이 없다며 오류가 나는 경우
data라는 state에 아직 값이 없는 경우, && 조건식은 false이며
Hello!
는 렌더링되지 않는다.function Component() {
const [data, setData] = useState("");
return (
<div class="App">
{
data && <p>Hello!</p>
}
</div>
)
}
📌 Case 2. useEffect() 100개 사용했는데도 오류가 나서 화나는 경우
useEffect를 사용해서 .img가 그려지는 작업이 끝난 후, 0번째 .img를 콘솔에 출력하고 싶었지만 오류가 났다.
const [img, setImg] = document.querySelectorAll('.img');
useEffect(() => {
console.log(img[0]);
}, [ img ]);
return (
<div>
{
data.map((item, idx) => {
return <div className="img" key={idx}></div>
})
}
</div>
)
Scroll.js:87 Uncaught TypeError: Cannot read properties of undefined
.img가 그려지기 전에는 img라는 state가 undefined이기 때문이다. 이 경우에 if 조건문을 사용하여 img 값이 존재하는지 확인만 해주면 쉽게 해결된다.
const [img, setImg] = document.querySelectorAll('.img');
useEffect(() => {
if (img) {
console.log(img[0]);
}
}, [ img ]);
return (
<div>
{
data.map((item, idx) => {
return <div className="img" key={idx}></div>
})
}
</div>
)
img state에 값이 있는 경우(true)에만 콘솔이 출력된다.
const rolling () => {
const $ele = document.querySelector(".ele");
// 지금 $ele가 있어? 있으면 margin top 적용해줘. 없음 말고. 에러는 사절임.
$ele?.getElementsByClassName.marginTop = "2em";
}
return (
<div className"App">
<div className="ele"></div>
</div>
)
ref를 사용하면 리렌더링 시에도 레퍼런스 값이 유지된다. 또한 레퍼런스 값이 업데이트 되더라도 리렌더링되지 않는다.
리액트 공식 문서에는 ref 사용을 지양해야한다고 명시되어 있지만, 직접 DOM 요소를 조작해야하는 상황이 있을 때에는 ref를 사용하면 쉽게 해결할 수 있다.
state와 ref 차이점
state의 변화는 리렌더링을 트리거하지만 ref는 아니다.
state는 비동기적이며 렌더링 완료되었을 때 사용 가능하지만, ref는 동기적이라 업데이트되면 바로 사용할 수 있다.
import { useRef } from 'react';
const LabPage = () => {
const anchorRef = useRef(null);
const anchorHandler = () => {
const anchor = anchorRef.current;
...
}
return (
<div className="anchor" ref={ anchorRef }>
...
</div>
)
}
profile