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+,建议的创建引用的方法是使用
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} />; } } |
组件安装后,
有关
如果您使用的是较早版本的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元素调用
通过将
曾经有一个API,其中
编辑于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,请添加
1 | const myRef = React.useRef<HTMLDivElement>(null); |
并如下所示使用它:
1 | return ; |
如果您不转发
在这种情况下,我总是这样做
抢裁判
只是添加了一种不同的方法-您可以简单地投射引用,例如:
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(); } } |
把它们放在一个物体上