TypeScript: React useRef 후크 입력

일반적인 구성 요소 흐름 외부에서 React 구성 요소의 DOM 요소를 명령적으로 수정해야 하는 경우가 있습니다.
가장 일반적인 예는 요소의 포커스를 관리하거나 React 애플리케이션 내에서 타사 라이브러리(특히 React로 작성되지 않은 라이브러리)를 사용하는 것입니다.

이 게시물은 입력 요소의 포커스 상태를 제어하는 ​​예에서 TypeScript에 후크를 입력하는 방법useRef을 보여줍니다.

버튼 클릭에 대한 입력에 수동으로 초점을 맞추려는 간단한 사용 사례가 있다고 가정해 보겠습니다. 구성 요소의 JS 코드는 다음과 같습니다.

export const CustomInput = () => {
    const inputRef = useRef(null);

    const onButtonClick = () => {
        inputRef.current.focus();
    };

    return (
        <div>
            <label htmlFor={"name"}>Name</label>
            <input id={"name"} placeholder={"Enter your name"} ref={inputRef}/>
            <button type={"button"} onClick={onButtonClick}>
                Focus input
            </button>
        </div>
    );
};

Focus input 버튼을 클릭하면 name 입력 필드에 초점이 맞춰집니다. 이제 이 구성 요소에 TypeScript를 사용하고 싶습니다. 첫 번째 단계로 파일 확장자를 .js에서 .tsx로 간단히 변경할 수 있습니다. 파일을 TS로 변환한 후 발생하는 오류는 Object is possibly null 줄에 대한 inputRef.current.focus();입니다. null 의 초기 값으로 inputRef 를 설정했기 때문에 이는 의미가 있습니다. 이 오류를 수정하려면 current를 호출하기 전에 inputReffocus 속성이 null이 아닌지 확인할 수 있습니다.

if (inputRef.current !== null) {
    inputRef.current.focus();
}


이는 optional chaining operator , ?로 단순화할 수 있습니다.

inputRef.current?.focus();

inputRef.current가 null( null 또는 undefined )인 경우 표현식이 단락되고 focus 메서드가 호출되지 않습니다(호출 결과를 변수에 할당하는 경우 다음과 같이 설정됨). undefined 이 경우).
이렇게 하면 유형 오류가 수정되지만 새 오류가 생성됩니다. Property 'focus' does not exist on type 'never'. 나중에 ref를 입력 요소에 할당하므로 처음에는 이상하게 보입니다. 문제는 TS가 기본값에서 inputRefnull 이외의 다른 값이 될 수 없다고 추론하고 그에 따라 입력한다는 것입니다. 그러나 우리는 ref가 나중에 입력 요소를 포함할 것이라는 것을 알고 있으므로 이 문제를 해결하려면 예상되는 요소 유형을 컴파일러에 명시적으로 알려야 합니다.

const inputRef = useRef<HTMLInputElement>(null);


이렇게 하면 문제가 해결되고 유형 오류가 발생하지 않습니다. 최종 코드는 다음과 같습니다.

export const CustomInput = () => {
    const inputRef = useRef<HTMLInputElement>(null);

    const onButtonClick = () => {
        inputRef.current?.focus();
    };

    return (
        <div>
            <label htmlFor={"name"}>Name</label>
            <input id={"name"} placeholder={"Enter your name"} ref={inputRef}/>
            <button type={"button"} onClick={onButtonClick}>
                Focus input
            </button>
        </div>
    );
};


useRef<HTMLInputElement>(null) 대 useRef<HTMLInputElement | 널>(널)


inputRef의 현재 입력은 해당 값을 재할당할 필요가 없는 경우에 잘 작동합니다. 이벤트 리스너를 입력에 수동으로 추가하려는 상황을 생각해 봅시다(타사 라이브러리로 작업할 때 유용함). 코드는 다음과 같습니다.

export const CustomInput = () => {
    const inputRef = useRef<HTMLInputElement>(null);

    useEffect(() => {
        inputRef.current = document.getElementById("name") as HTMLInputElement;
        inputRef.current.addEventListener("keypress", onKeyPress);

        return () => {
            inputRef.current?.removeEventListener("keypress", onKeyPress);
        };
    }, []);

    const onKeyPress = () => { /* Handle input key press */ };

    return (
        <div>
            <label htmlFor={"name"}>Name</label>
            <input id={"name"} placeholder={"Enter your name"}/>
            <button type={"button"}>Focus input</button>
        </div>
    );
};

document.getElementById 의 결과를 HTMLInputElement 로 캐스트해야 합니다. TS는 이 경우 올바른 요소 유형을 유추할 수 없고 기본적으로 보다 일반적인 HTMLElement 로 지정되기 때문입니다. 그러나 이 경우 요소가 입력 요소라는 것을 알고 있으므로 그에 따라 캐스팅하는 것이 안전합니다. 코드는 괜찮아 보이지만 TS 오류가 발생합니다. Cannot assign to 'current' because it is a read-only property. 에 대한 유형 정의를 자세히 살펴보면 다음과 같이 정의됩니다.

interface RefObject<T> {
    readonly current: T | null;
}


그렇다면 어떻게 변경 가능하게 만들 수 있습니까? current 에 대한 유형 정의에 따라 실제로 몇 가지 과부하가 있음을 알 수 있으며 그 중 가장 중요한 것은 다음과 같습니다.

function useRef<T>(initialValue: T): MutableRefObject<T>;
function useRef<T>(initialValue: T | null): RefObject<T>;

React.RefObject<HTMLInputElement>.current:any를 기본 매개변수로 지정하지만 유형 매개변수에 포함하지 않는 경우 React.RefObject에 대한 두 번째 오버로드를 일치시켜 읽기 전용useRef 속성이 있는 ref 개체를 가져옵니다. 이를 수정하려면 유형 매개변수에 null를 포함해야 합니다.

const inputRef = useRef<HTMLInputElement | null>(null);


이것은 useRef 오버로드와 일치하고 유형 문제를 수정합니다. 후크에 대한 유형 정의에 편리한 참고 사항도 있습니다.

Usage note: if you need the result of useRef to be directly mutable, include | null in the type of the generic argument.


코드의 최종 버전은 다음과 같습니다.

export const CustomInput = () => {
    const inputRef = useRef<HTMLInputElement | null>(null);

    useEffect(() => {
        inputRef.current = document.getElementById("name") as HTMLInputElement;
        inputRef.current.addEventListener("keypress", onKeyPress);

        return () => {
            inputRef.current?.removeEventListener("keypress", onKeyPress);
        };
    }, []);

    const onKeyPress = () => { /* Handle input key press */ };

    return (
        <div>
            <label htmlFor={"name"}>Name</label>
            <input id={"name"} placeholder={"Enter your name"}/>
            <button type={"button"}>Focus input</button>
        </div>
    );
};

좋은 웹페이지 즐겨찾기