더 알아보기/기능

[React + Typescript] 부모 자식 간에 useRef 사용하는 방법

은돌1113 2023. 10. 19. 15:13

React와 Typescript를 사용한 프로젝트에서 input에 useRef를 사용하던 중 새롭게 알게된 내용을 정리했습니다.

 

동일한 컴포넌트에서 useRef를 사용하는 경우 이 내용이 큰 도움이 되지 않을 수 있지만,

부모 컴포넌트에서 자식 컴포넌트에 prosp로 ref를 넘기고, 해당 ref에 접근하여 DOM을 조작하거나 값을 얻어야 하는 경우에 도움이 될 듯 합니다.

 

실행 화면


코드

  • useRef() : DOM 취득 용도로 HTMLInputElement 타입을 설정하고, 초깃값으로 null을 설정한다.
// Parent.tsx

import { useState, useEffect, useRef } from "react";
import Input from "./Input";
import Button from "../elements/Button";

interface UserInfo {
  name: string;
  age: number;
}

const Parent = () => {
  const nameRef = useRef<HTMLInputElement>(null);

  const [userInfo, setUserInfo] = useState<UserInfo>({
    name: "홍길동",
    age: 20,
  });

  useEffect(() => {
    if (nameRef.current) {
      nameRef.current.focus();
    }
  }, [nameRef]);

  const inputHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
    const name = e.target.name;
    const value = e.target.value;

    setUserInfo((prev) => {
      return { ...prev, [name]: value };
    });
  };

  const submit = () => {
    alert(
      `회원의 이름은 ${userInfo.name}이고, 나이는 ${userInfo.age}세입니다.`
    );
  };

  return (
    <div>
      <Input
        name="name"
        value={userInfo.name}
        onChange={inputHandler}
        ref={nameRef}
      />
      <Input
        name="age"
        value={userInfo.age}
        onChange={inputHandler}
        enter={submit}
      />
      <Button onClick={submit}>저장하기</Button>
    </div>
  );
};

export default Parent;
  • 부모에서 자식 컴포넌트에 props로 ref를 넘겨주면, React에 forwardRef와 ForwardedRef(type)를 import 받고, 두 번째 인자에 ref: ForwadedRef<HTMLInputElement>를 삽입하면 정상적으로 적용됩니다.
// Input.tsx

import { forwardRef, type ForwardedRef } from "react";
import styled from "@emotion/styled/macro";

interface Props {
  type?: string;
  value: string | number;
  name: string;
  onChange: any;
  enter?: any;
}

const Input = forwardRef(
  (
    { type = "string", value, name, onChange, enter }: Props,
    ref: ForwardedRef<HTMLInputElement>
  ) => {
    const onKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => {
      if (e.key === "Enter") {
        enter();
      }
    };

    return (
      <InputWrap
        type={type}
        value={value}
        name={name}
        onChange={onChange}
        onKeyPress={onKeyPress}
        ref={ref}
      />
    );
  }
);

const InputWrap = styled.input`
  width: calc(100% - 30px);
  height: 49px;
  text-align: left;
  color: #212529;
  outline: none;
  border: 2px solid #eee;
  background: #fbfbfb;
  border-radius: 6px;
  padding: 0 15px;
  margin: 10px 0;

  &:focus,
  &:focus-visible {
    border: 2px solid var(--base-color);
    background: white;
  }
`;

export default Input;

참고

 

[React] TypeScript useRef 사용법 (+ ref 객체 타입)

# TypeScript에서 useRef 사용 방법 TypeScript에서 useRef 사용시, 아래와 같이 제네릭과 초기값을 설정해야 한다. 1. 값 저장 용도 - 제네릭 : 값의 타입을 넣어준다. - 초기값 : 반드시 타입에 맞는 초기값

curryyou.tistory.com

 

Typescript에서 React forwardRef 타입 에러

Typescript + React에서 Component에 forwardRef를 씌울려고 했는데...Argument of type '({ mediaStream }: VideoProps, ref: RefObject) => Element' is not assignable t

velog.io