关于reactjs:如何在带有Typescript的React中使用refs

How to use refs in React with Typescript

我在React中使用Typescript。 我在理解如何使用refs方面遇到麻烦,以便相对于refs引用的react节点获得静态类型和智能感知。 我的代码如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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 (
       
            Hello World
            <input type="text" ref="stepInput" />
            <button onClick={() => this.incrementCounter()}>Increment</button>
            Count : {this.state.count}
       
    );
}}

如果您使用的是React 16.3+,建议的创建引用的方法是使用React.createRef()

1
2
3
4
5
6
7
8
9
10
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),或者需要更精细地控制引用的设置和取消设置时间,则可以使用"回调引用"。

1
2
3
4
5
6
7
8
9
10
11
12
13
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将使用DOM元素调用ref回调,并在卸载时使用null调用它。因此,例如,您可以简单地使用this.stepInput访问它。

通过将ref回调定义为类上的绑定方法,而不是内联函数(如此答案的先前版本),可以避免在更新过程中两次调用该回调。

曾经有一个API,其中ref属性是字符串(请参阅Akshar Patel的答案),但是由于某些问题,强烈建议不要使用字符串引用,最终将其删除。

编辑于2018年5月22日,以在React 16.3中添加执行引用的新方法。感谢@apieceofbart指出有一种新方法。


一种方法(我一直在做的)是手动设置:

1
2
3
4
refs: {
    [string: string]: any;
    stepInput:any;
}

那么您甚至可以将其包装在更好的getter函数中(例如此处):

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


从React 16.3开始,添加引用的方法就是使用Jeff Bowen在回答中指出的React.createRef。但是,您可以利用Typescript更好地键入引用。

在您的示例中,您在输入元素上使用了ref。因此,他们这样做的方式是:

1
2
3
4
5
6
7
8
9
10
11
12
13
class SomeComponent extends React.Component<IProps, IState> {
    private inputRef: React.RefObject<HTMLInputElement>;
    constructor() {
        ...
        this.inputRef = React.createRef();
    }

    ...

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

通过在希望使用该引用的情况下执行此操作,可以访问所有输入法:

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

您也可以在自定义组件上使用它:

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

然后可以访问道具:

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

编辑:这已不再是使用Typescript引用的正确方法。查看Jeff Bowen的答案,并对其进行投票以提高其可见度。

找到了问题的答案。在类中使用下面的引用。

1
2
3
4
refs: {
    [key: string]: (Element);
    stepInput: (HTMLInputElement);
}

感谢@basarat指出正确的方向。


要按照React文档的建议使用回调样式(https://facebook.github.io/react/docs/refs-and-the-dom.html),可以在类的属性上添加定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
2
3
4
5
6
7
8
9
private divRef: HTMLDivElement | null = null

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

render() {
    return
}

...


缺少完整的示例,这是我的小测试脚本,用于在使用React和TypeScript时获取用户输入。部分基于其他评论以及此链接https://medium.com/@basarat/strongly-typed-refs-for-react-typescript-9a07419f807#.cdrghertm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/// <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 (
           
                Server time: { this.state.time }
                <input type="text" ref={ a => this.inputs.userFormat = a } defaultValue="s"></input>
                <button onClick={ this._buttonClick.bind(this) }>GetTime</button>
           
        );
    }

    // 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 });
        }
    });
}

}


如果您使用的是React.FC,请添加HTMLDivElement接口:

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

并如下所示使用它:

1
return ;

如果您不转发ref,则在Props界面中,您需要使用import React, { RefObject } from 'react';中的RefObject类型


在这种情况下,我总是这样做
抢裁判

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


只是添加了一种不同的方法-您可以简单地投射引用,例如:

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

从React类型定义

1
2
3
4
5
    type ReactInstance = Component | Element;
....
    refs: {
            [key: string]: ReactInstance
    };

因此您可以按以下方式访问refs元素

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

没有重新定义refs索引。

正如@manakor提到的那样,您会收到类似

Property 'stepInput' does not exist on type '{ [key: string]:
Component | Element; }

如果您重新定义引用(取决于您使用的IDE和ts版本)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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();
    }
}

把它们放在一个物体上