TypescriptとReactでrefを使用する方法


139

TypescriptとReactを使用しています。refが参照する反応ノードに関して静的型付けとインテリセンスを取得するために、refの使用方法を理解するのに問題があります。私のコードは次のとおりです。

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

の詳細についてはRefObject@ apieceofbartの回答を参照するか、PR createRef()が追加されました。


Reactの以前のバージョン(<16.3)を使用している場合、または参照が設定および設定解除されるタイミングをより詳細に制御する必要がある場合は、「コールバック参照」を使用できます。

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(この回答の以前のバージョンのように)インライン関数ではなくクラスのバインドされたメソッドとしてコールバックを定義することにより、更新中にコールバックが2回呼び出されるのを回避できます。


そこにするために使用 API ref(参照属性が文字列だったAksharパテルの答えを)、それに起因するいくつか の問題、文字列、参考文献を強く推奨され、最終的に削除されます。


2018年5月22日を編集して、React 16.3で参照を行う新しい方法を追加しました。新しい方法があったことを指摘してくれた@apieceofbartに感謝します。


これは推奨される方法です。以下のrefsclass属性を使用した例は、今後のReactバージョンで非推奨になります。
Jimi Pajala、2018年

1
これはすでに古い方法であることに注意してください:)現在はReact.createRef()を使用しています
apieceofbart

@apieceofbart頭を上げてくれてありがとう。新しい方法を含むように回答を更新しました。
ジェフボーウェン

2
私はあなたの答えにタイプスクリプトについて何も見ていません、私は別の答えを追加します
apieceofbart

おっと。私の元の答えにはTypescriptがありましたが、新しいものに含めるのを忘れていました。それを再度追加し、回答にもリンクしました。ありがとう。
ジェフボーウェン

30

1つの方法(私はこれを行っています)は手動でセットアップすることです:

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

次に、これをより良いゲッター関数でラップすることもできます(例:ここ)。

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

1
@basaratに感謝します。私はあなたの解決策を試しましたが、私はこのエラーを受け取ります 'タイプ要素はタイプ' HTMLInputElementに割り当てることができません。Element型がElement要素にありません」
Akshar Patel 2015

新しいバージョンのreact-dom定義の問題である可能性があります。当面はアサーションとして使用してください
バサラト2015年

明らかにanyここでは必須ではありません。私が使用してHTMLInputElementいると思われるほとんどの例。明白なことだけを述べますが、refがReactコンポーネント(つまり、PeoplePicker)にある場合、そのコンポーネントをタイプとして使用して、タイピングを取得できます。
Joe Martella、2017

24

React 16.3以降、参照を追加する方法は、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で参照を使用する正しい方法ではありません。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 2016

@NikSumeiko、refsオブジェクトに[key: string]エントリしかなかったため、エラーが発生しました。
Joe Martella、2017

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
}

注:この場合useRefnullで初期化しないでください。それはなるだろう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)が、RefObjectcurrentマークされたタイプを作成しreadonlyます。前者は、たとえば外部ライブラリと組み合わせて、ref内の現在のDOMノードを変更する必要がある場合に使用できます。なしで書くこともできasますuseRef<HTMLInputElement | null>(null)。後者は、ほとんどの場合で使用されるように、ReactマネージドDOMノードに適しています。Reactはノードをrefs自体に保存します。これらの値を変更する必要はありません。
ford04

1
説明をありがとう。
ksav

7

を使用している場合はReact.FCHTMLDivElementインターフェースを追加します。

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']);

参照インデックスの再定義なし。

@manakorが述べたように、次のようなエラーが発生する可能性があります

プロパティ 'stepInput'はタイプ '{[キー:文字列]:コンポーネントに存在しません| 素子; }

refsを再定義する場合(使用するIDEおよびtsのバージョンによって異なります)



0

私はいつもこれをします、その場合、参照をつかむために

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


入力を許可:HTMLInputElement = ReactDOM.findDOMNode <HTMLInputElement>(this.refs ['input']);
user2662112 2017

0

を転送しない場合refは、PropsインターフェースでRefObject<CmpType>type from を使用する必要があります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」の選択です。
ダグ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.