개체가 'null'인 것 같습니다.
interface IProps {
targetCamp: ICampDetail;
}
const ContentsSection = ({ targetCamp }: IProps) => {
const containerRef = useRef<HTMLElement>(null);
const imgRef = useRef<HTMLElement>(null);
const [height, setHeight] = useState<number>(0);
const onloadImages = useCallback(() => {
const imgs = imgRef.current.querySelectorAll('img');
for (let i = 0; i < imgs.length; i++) {
imgs[i].onload = () => {
if (i === imgs.length - 1) getHeight();
};
}
}, []);
const getHeight = () => {
setHeight(containerRef.current.clientHeight);
};
useEffect(() => {
targetCamp && onloadImages();
}, [onloadImages, targetCamp]);
return (
<Container ref={containerRef}>
{targetCamp && (
<ImageBox ref={imgRef}>
{targetCamp.images.map((img, index) => (
<img key={index} src={img} art="상세페이지 이미지" />
))}
</ImageBox>
)}
</Container>
);
ContentsSection
컴포넌트 안에서, ContentsSection
의 clientHeight값과, ImageBox
안의 이미지들을 구하고 싶습니다. Container
와 ImageBox
컴포넌트를 useRef로 받습니다. containerRef
와 imgRef
모두 DOM을 참조하기 위함입니다.
containerRef.current
imgRef.current
이 부분에서, 개체가 null인 것 같다는 오류가 뜹니다.
interface IProps {
targetCamp: ICampDetail;
}
const ContentsSection = ({ targetCamp }: IProps) => {
const containerRef = useRef<HTMLElement>(null);
const imgRef = useRef<HTMLElement>(null);
const [height, setHeight] = useState<number>(0);
const onloadImages = useCallback(() => {
if (imgRef.current) { // if문 추가
const imgs = imgRef.current.querySelectorAll('img');
for (let i = 0; i < imgs.length; i++) {
imgs[i].onload = () => {
if (i === imgs.length - 1) getHeight();
};
}
}
}, []);
const getHeight = () => {
containerRef.current && // AND연산자 추가
setHeight(containerRef.current.clientHeight);
};
useEffect(() => {
targetCamp && onloadImages();
}, [onloadImages, targetCamp]);
return (
<Container ref={containerRef}>
{targetCamp && (
<ImageBox ref={imgRef}>
{targetCamp.images.map((img, index) => (
<img key={index} src={img} art="상세페이지 이미지" />
))}
</ImageBox>
)}
</Container>
);
if문과 AND연산자를 이용했습니다.
초기값이 null이어서, null이 반환되면 안되니 조건을 추가해서 에러를 해결했습니다.
useRef를 사용하다보면, 심심찮게 에러를 뿜어내고는 하는데
이 참에, useRef 대해 이 문서를 보고 자세히 공부를 해봐야 겠다고 생각하여,
https://driip.me/7126d5d5-1937-44a8-98ed-f9065a7c35b5
이 문서를 보고 공부를 해보았습니다.
interface MutableRefObject<T> {
current: T;
}
interface RefObject<T> {
readonly current: T | null;
}
useRef의 반환타입에는 2가지가 있고, 그저 함수 초깃값을 .current에 저장할 뿐입니다.
useRef<T>(initialValue: T): MutableRefObject<T>; // 1
useRef<T>(initialValue: T|null): RefObject<T>; // 2
useRef<T = undefined>(): MutableRefObject<T | undefined>; // 3
MutableRefObject<T>
를 반환RefObject<T>
를 반환MutableRefObject<T | undefined>
를 반환 MutableRefObject<T>
반환const localValRef = useRef<number>(숫자)
[예시코드]
: 버튼을 클릭할 경우 localVarRef.current의 값이 1씩 증가하는 코드 입니다.
import React, { useRef } from "react";
const App = () => {
const localVarRef = useRef<number>(0);
const handleButtonClick = () => {
if (localVarRef.current) {
localVarRef.current += 1;
console.log(localVarRef.current);
}
};
return (
<div className="App">
<button onClick={handleButtonClick}>+1</button>
</div>
);
};
export default App;
RefObject<T>
반환const containerRef = useRef<HTMLElement>(null)
내 코드에서는 DOM을 참조하고 싶은거니까, RefObject<T>
를 반환합니다.
RefObject<T>
는 값을 수정할 수 없다고 하는데, 왜 정상적으로 작동할까?정의 상 current 프로퍼티만 읽기 전용으로, current 프로퍼티의 하위 프로퍼티는 여전히 수정 가능하다. 이는 readonly가 shallow(얕은객체복사)이기 때문입니다.
const containerRef = useRef() as React.MutableRefObject<HTMLElement>;
const imgRef = useRef() as React.MutableRefObject<HTMLElement>;
useRef의 타입을 이렇게 설정하면, MutableRefObject<T>
를 반환하는 것을
확인하였습니다. 이 경우, onloadImages
와 getHeight
에 각각 if문이나,
AND연산자를 걸지 않아도 동작합니다.
const onloadImages = useCallback(() => {
const imgs = imgRef.current.querySelectorAll('img');
for (let i = 0; i < imgs.length; i++) {
imgs[i].onload = () => {
if (i === imgs.length - 1) getHeight();
};
}
}, []);
const getHeight = () => {
setHeight(containerRef.current.clientHeight);
};
정리하면 다음과 같습니다.
const localVarRef = useRef<여기>(저기);
로컬 변수 용도로 useRef를 사용하는 경우, MutableRefObject<T>
를 사용해야 하므로
제네릭 타입과 같은 타입의 초깃값을 넣어주자. (여기와 저기를 같게)
const inputRef = useRef<HTMLInputElement>(null);
DOM을 직접 조작하기 위해 프로퍼티로 useRef 객체를 사용할 경우, RefObject<T>
를 사용해야 하므로 초깃값으로 null을 넣어주자.
useRef() as React.MutableRefObject<T>
MutableRefObject<T>
를 반환한다!