Typescript로 React에서 ref를 사용하는 방법


139

React와 함께 Typescript를 사용하고 있습니다. refs에서 참조하는 반응 노드와 관련하여 정적 타이핑 및 지능을 얻기 위해 refs를 사용하는 방법을 이해하는 데 문제가 있습니다. 내 코드는 다음과 같습니다.

import * as React from 'react';

interface AppState {
    count: number;
}

interface AppProps {
    steps: number;
}

interface AppRefs {
    stepInput: HTMLInputElement;
}

export default class TestApp extends React.Component<AppProps, AppState> {

constructor(props: AppProps) {
    super(props);
    this.state = {
        count: 0
    };
}

incrementCounter() {
    this.setState({count: this.state.count + 1});
}

render() {
    return (
        <div>
            <h1>Hello World</h1>
            <input type="text" ref="stepInput" />
            <button onClick={() => this.incrementCounter()}>Increment</button>
            Count : {this.state.count}
        </div>
    );
}}

답변:


183

React 16.3 이상을 사용하는 경우 제안 된 참조 생성 방법React.createRef().

class TestApp extends React.Component<AppProps, AppState> {
    private stepInput: React.RefObject<HTMLInputElement>;
    constructor(props) {
        super(props);
        this.stepInput = React.createRef();
    }
    render() {
        return <input type="text" ref={this.stepInput} />;
    }
}

구성 요소가 마운트되면 ref속성의 current속성이 참조 된 구성 요소 / DOM 요소에 할당 null되고 마운트 해제시 다시 할당됩니다 . 예를 들어 다음을 사용하여 액세스 할 수 있습니다.this.stepInput.current .

에 대한 자세한 내용은 @apieceofbart의 답변을RefObject 참조 하거나 PR 이 추가되었습니다. createRef()


이전 버전의 React (<16.3)를 사용 중이거나 ref가 설정되고 설정 해제되는시기를보다 세밀하게 제어해야하는 경우 "callback refs"를 사용할 수 있습니다 .

class TestApp extends React.Component<AppProps, AppState> {
    private stepInput: HTMLInputElement;
    constructor(props) {
        super(props);
        this.stepInput = null;
        this.setStepInputRef = element => {
            this.stepInput = element;
        };
    }
    render() {
        return <input type="text" ref={this.setStepInputRef} />
    }
}

컴포넌트가 마운트되면 React는 refDOM 요소를 사용 하여 콜백을 호출 null하고 마운트 해제시이를 호출합니다 . 예를 들어 간단히 this.stepInput.

ref( 이 답변 의 이전 버전 에서와 같이) 인라인 함수와 반대로 클래스의 바인딩 된 메서드로 콜백 을 정의하면 업데이트 중에 콜백 이 두 번 호출되는 것을 방지 할 수 있습니다.


로 사용 은 An API ref(참조 속성이 문자열였다을 Akshar 파텔의 답변을 ),하지만 인해 몇 가지 문제 , 문자열 심판은 권장하지하고 결국 제거됩니다.


2018 년 5 월 22 일에 React 16.3에서 ref를 수행하는 새로운 방법을 추가하기 위해 편집되었습니다. 새로운 방법이 있음을 지적 해 주신 @apieceofbart에게 감사드립니다.


이것이 선호되는 방법임을 주목하십시오. refs클래스 속성이있는 아래 예제 는 향후 React 버전에서 더 이상 사용되지 않습니다.
Jimi Pajala

1
이것은 이미 오래된 방법입니다. :) 현재는 React.createRef ()를 사용하는 것입니다
apieceofbart

@apieceofbart 머리를 올려 주셔서 감사합니다. 새로운 방법을 포함하도록 답변을 업데이트했습니다.
Jeff Bowen

2
난 그냥 다른 답변 추가 할 것입니다, 당신의 대답에 타이프에 대해 아무것도 표시되지 않습니다
apieceofbart

이런. 내 원래 답변에 Typescript가 있었지만 새 답변에 포함하는 것을 잊었습니다. 다시 추가하고 답변에 연결되었습니다. 감사.
Jeff Bowen

30

한 가지 방법 ( 내가했던 )은 수동으로 설정하는 것입니다.

refs: {
    [string: string]: any;
    stepInput:any;
}

그런 다음 더 좋은 getter 함수 (예 : 여기 ) 로이를 래핑 할 수도 있습니다 .

stepInput = (): HTMLInputElement => ReactDOM.findDOMNode(this.refs.stepInput);

1
감사합니다 @basarat. 솔루션을 시도했지만 '유형 요소가'HTMLInputElement 유형에 할당 할 수 없습니다. 요소 유형에 속성 수락이 없습니다. ''
Akshar Patel

최신 버전의 react-dom 정의 문제 일 수 있습니다. 그 동안 주장으로 사용
basarat

분명히 any여기서 필수는 아닙니다. 내가 보는 대부분의 예는 HTMLInputElement. 명백한 것을 말하지만 ref가 React 구성 요소 (예 PeoplePicker:)에있는 경우 해당 구성 요소를 유형으로 사용하여 입력을 얻을 수 있습니다.
Joe Martella

24

React 16.3부터 ref를 추가하는 방법 은 Jeff Bowen이 답변에서 지적한대로 React.createRef 를 사용하는 것입니다. 그러나 Typescript를 활용하여 심판을 더 잘 입력 할 수 있습니다.

귀하의 예에서는 입력 요소에 ref를 사용하고 있습니다. 그래서 그들이 할 방법은 다음과 같습니다.

class SomeComponent extends React.Component<IProps, IState> {
    private inputRef: React.RefObject<HTMLInputElement>;
    constructor() {
        ...
        this.inputRef = React.createRef();
    }

    ...

    render() {
        <input type="text" ref={this.inputRef} />;
    }
}

해당 참조를 사용하고 싶을 때 이렇게하면 모든 입력 방법에 액세스 할 수 있습니다.

someMethod() {
    this.inputRef.current.focus(); // 'current' is input node, autocompletion, yay!
}

사용자 지정 구성 요소에서도 사용할 수 있습니다.

private componentRef: React.RefObject<React.Component<IProps>>;

예를 들어 소품에 대한 액세스 권한이 있습니다.

this.componentRef.current.props; // 'props' satisfy IProps interface

17

편집 : 이것은 더 이상 Typescript와 함께 ref를 사용하는 올바른 방법이 아닙니다. Jeff Bowen의 답변을보고 찬성하여 가시성을 높입니다.

문제에 대한 답을 찾았습니다. 클래스 내부에서 아래와 같이 refs를 사용하십시오.

refs: {
    [key: string]: (Element);
    stepInput: (HTMLInputElement);
}

올바른 방향을 가리키는 @basarat에게 감사드립니다.


2
Property 'stepInput' does not exist on type '{ [key: string]: Component<any, any> | Element; }'액세스를 시도 할 때 여전히 나옵니다 this.refs.stepInput.
Nik Sumeiko

@NikSumeiko, refs개체에 [key: string]항목 만 있기 때문에 해당 오류가 발생했습니다 .
Joe Martella

9

React.createRef (클래스 구성 요소)

class ClassApp extends React.Component {
  inputRef = React.createRef<HTMLInputElement>();
  
  render() {
    return <input type="text" ref={this.inputRef} />
  }
}

참고 : 여기 에서 이전 String Refs 레거시 API 생략 ...


React.useRef (후크 / 기능 부품)

DOM 노드에 대한 읽기 전용 참조 :
const FunctionApp = () => {
  const inputRef = React.useRef<HTMLInputElement>(null) // note the passed in `null` arg
  return <input type="text" ref={inputRef} />
}
임의의 저장된 값에 대한 변경 가능한 참조 :
const FunctionApp = () => {
  const renderCountRef = useRef(0)
  useEffect(() => {
    renderCountRef.current += 1
  })
  // ... other render code
}

참고 : 음주 초기화하지 useRef으로 null이 경우이다. renderCountRef유형 을 만듭니다 readonly( 예제 참조 ). 초기 값 으로 제공 해야하는 경우 다음을 null수행하십시오.

const renderCountRef = useRef<number | null>(null)

콜백 참조 (둘 다 작동)

// Function component example 
const FunctionApp = () => {
  const handleDomNodeChange = (domNode: HTMLInputElement | null) => {
    // ... do something with changed dom node.
  }
  return <input type="text" ref={handleDomNodeChange} />
}

놀이터 샘플


useRef() as MutableRefObject<HTMLInputElement>과 의 차이점은 무엇입니까 useRef<HTMLInputElement>(null)?
ksav

2
좋은 질문-의 current속성은 MutableRefObject<HTMLInputElement>수정할 수 있지만 으로 표시된 유형을 useRef<HTMLInputElement>(null)만듭니다 . 예를 들어 외부 라이브러리와 결합하여 refs에서 현재 DOM 노드를 직접 변경해야하는 경우 전자를 사용할 수 있습니다. 또한없이 쓸 수있다 : . 후자는 대부분의 경우에 사용되는 React 관리 DOM 노드에 더 나은 선택입니다. React는 노드를 refs 자체에 저장하므로 이러한 값을 변경하는 것을 원치 않습니다. RefObjectcurrentreadonlyasuseRef<HTMLInputElement | null>(null)
ford04

1
설명해 주셔서 감사합니다.
ksav

7

을 사용하는 경우 인터페이스를 React.FC추가하십시오 HTMLDivElement.

const myRef = React.useRef<HTMLDivElement>(null);

다음과 같이 사용하십시오.

return <div ref={myRef} />;

1
감사. 이것을 발견하는 사람을위한 또 다른 팁은 요소를 확인하는 것입니다. 이 예제는 DIV 요소의 사용법을 참조합니다. 예를 들어 양식은 다음을 사용합니다.-const formRef = React.useRef <HTMLFormElement> (null);
Nick Taras

1
감사합니다 감사합니다 감사합니다 감사합니다 감사합니다 감사합니다. 감사합니다.
Ambrown

2

React 문서에서 권장 하는 콜백 스타일 ( https://facebook.github.io/react/docs/refs-and-the-dom.html ) 을 사용하려면 클래스에 속성에 대한 정의를 추가 할 수 있습니다.

export class Foo extends React.Component<{}, {}> {
// You don't need to use 'references' as the name
references: {
    // If you are using other components be more specific than HTMLInputElement
    myRef: HTMLInputElement;
} = {
    myRef: null
}
...
 myFunction() {
    // Use like this
    this.references.myRef.focus();
}
...
render() {
    return(<input ref={(i: any) => { this.references.myRef = i; }}/>)
}

1

완전한 예제가 부족한 것은 React 및 TypeScript로 작업 할 때 사용자 입력을 얻기위한 작은 테스트 스크립트입니다. 부분적으로 다른 의견과이 링크를 기반으로 함 https://medium.com/@basarat/strongly-typed-refs-for-react-typescript-9a07419f807#.cdrghertm

/// <reference path="typings/react/react-global.d.ts" />

// Init our code using jquery on document ready
$(function () {
    ReactDOM.render(<ServerTime />, document.getElementById("reactTest"));
});

interface IServerTimeProps {
}

interface IServerTimeState {
    time: string;
}

interface IServerTimeInputs {
    userFormat?: HTMLInputElement;
}

class ServerTime extends React.Component<IServerTimeProps, IServerTimeState> {
    inputs: IServerTimeInputs = {};

    constructor() {
        super();
        this.state = { time: "unknown" }
    }

    render() {
        return (
            <div>
                <div>Server time: { this.state.time }</div>
                <input type="text" ref={ a => this.inputs.userFormat = a } defaultValue="s" ></input>
                <button onClick={ this._buttonClick.bind(this) }>GetTime</button>
            </div>
        );
    }

    // Update state with value from server
    _buttonClick(): void {
    alert(`Format:${this.inputs.userFormat.value}`);

        // This part requires a listening web server to work, but alert shows the user input
    jQuery.ajax({
        method: "POST",
        data: { format: this.inputs.userFormat.value },
        url: "/Home/ServerTime",
        success: (result) => {
            this.setState({ time : result });
        }
    });
}

}


1

typescript 사용자의 경우 생성자가 필요하지 않습니다.

...

private divRef: HTMLDivElement | null = null

getDivRef = (ref: HTMLDivElement | null): void => {
    this.divRef = ref
}

render() {
    return <div ref={this.getDivRef} />
}

...


0

React 유형 정의에서

    type ReactInstance = Component<any, any> | Element;
....
    refs: {
            [key: string]: ReactInstance
    };

따라서 다음과 같이 refs 요소에 액세스 할 수 있습니다.

stepInput = () => ReactDOM.findDOMNode(this.refs['stepInput']);

refs 인덱스의 재정의없이.

@manakor가 언급했듯이 다음과 같은 오류가 발생할 수 있습니다.

속성 'stepInput'이 '{[key : string] 유형에 없습니다. 구성 요소 | 요소; }

refs를 재정의하는 경우 (사용하는 IDE 및 TS 버전에 따라 다름)


0

다른 접근 방식을 추가하기 위해 다음과 같이 간단히 ref를 캐스팅 할 수 있습니다.

let myInputElement: Element = this.refs["myInput"] as Element

0

나는 항상 이것을한다,이 경우 심판을 잡기 위해

let input: HTMLInputElement = ReactDOM.findDOMNode<HTMLInputElement>(this.refs.input);


입력하자 : HTMLInputElement = ReactDOM.findDOMNode <HTMLInputElement> (this.refs [ 'input']);
user2662112

0

을 전달하지 않으려면 refProps 인터페이스 RefObject<CmpType>에서 유형 을 사용해야 합니다.import React, { RefObject } from 'react';


0

요소 배열이있을 때이를 수행하는 방법을 찾는 사람들을 위해 :

const textInputRefs = useRef<(HTMLDivElement | null)[]>([])

...

const onClickFocus = (event: React.BaseSyntheticEvent, index: number) => {
    textInputRefs.current[index]?.focus()
};

...

{items.map((item, index) => (
    <textInput
        inputRef={(ref) => textInputs.current[index] = ref}
    />
    <Button
        onClick={event => onClickFocus(event, index)}
    />
}

-1
class SelfFocusingInput extends React.Component<{ value: string, onChange: (value: string) => any }, {}>{
    ctrls: {
        input?: HTMLInputElement;
    } = {};
    render() {
        return (
            <input
                ref={(input) => this.ctrls.input = input}
                value={this.props.value}
                onChange={(e) => { this.props.onChange(this.ctrls.input.value) } }
                />
        );
    }
    componentDidMount() {
        this.ctrls.input.focus();
    }
}

물건에 넣어


1
답변을 설명해주십시오
AesSedai101

이 대답은 ctrls.input을 강력한 유형의 요소로 설정하는 것입니다. 이것은 더 나은 "Typescript"선택입니다.
Doug
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.