如何在与Typecript的React中使用引用

Aks*_*tel 88 typescript reactjs

我正在使用带有React的Typescript.我无法理解如何使用refs以获得关于refs引用的react节点的静态类型和intellisense.我的代码如下.

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>
    );
}}
Run Code Online (Sandbox Code Playgroud)

Jef*_*wen 136

如果您使用的是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} />;
    }
}
Run Code Online (Sandbox Code Playgroud)

当组件安装时,ref属性的current属性将被分配给引用的组件/ DOM元素,并null在卸载时分配回来.因此,例如,您可以使用它来访问它this.stepInput.current.

有关更多信息RefObject,请参阅@ apieceofbart的答案或添加PR createRef().


如果您使用的是早期版本的React(<16.3)或者需要更多细粒度控制何时设置和取消设置引用,则可以使用"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} />
    }
}
Run Code Online (Sandbox Code Playgroud)

当组件安装时,React将ref使用DOM元素调用回调,并null在卸载时调用它.因此,例如,您只需使用即可访问它this.stepInput.

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


曾经是一个API,其中ref属性是一个字符串(见AKSHAR特尔的答案),但由于一些 问题,串裁判的强烈反对,并最终将被删除.


编辑于2018年5月22日,在React 16.3中添加了新的参考方式.谢谢@apieceofbart指出有一种新的方式.

  • 我只是在你的答案中没有看到任何关于打字稿的内容,我会添加另一个答案 (2认同)
  • 您还可以使用“React.RefObject&lt;HTMLElement&gt;” (2认同)

for*_*d04 38

React.createRef (班级)

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

React.useRef (钩子/函数组合。)

a) 对 React 管理的 DOM 节点使用只读引用:
const FunctionApp = () => {
  // note the passed-in `null` arg ----------------v
  const inputRef = React.useRef<HTMLInputElement>(null)
  return <input type="text" ref={inputRef} />
}
Run Code Online (Sandbox Code Playgroud)

inputRef.currentreadonly通过用 初始化其值成为一个属性null

b)对类似于实例变量的任意存储值使用可变引用
const FunctionApp = () => {
  const renderCountRef = useRef(0)
  useEffect(() => {
    renderCountRef.current += 1
  })
  // ... other render code
}
Run Code Online (Sandbox Code Playgroud)

注意:在这种情况下不要初始化useRefwith null- 它会生成renderCountRef类型readonly(参见示例)。如果您需要提供null初始值,请执行以下操作:

const renderCountRef = useRef<number | null>(null)
Run Code Online (Sandbox Code Playgroud)

回调引用(两者)

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

注意:字符串引用被认为是遗留的,在本答案的范围内被省略。

游乐场示例

  • 好问题 - 可以修改 MutableRefObject&lt;HTMLInputElement&gt; 的 current 属性,而 useRef&lt;HTMLInputElement&gt;(null) 创建一个 RefObject 类型,并将 current 标记为 readonly 。如果您需要自己更改 refs 中的当前 DOM 节点(例如与外部库结合使用),则可以使用前者。也可以不使用`as`来编写:`useRef&lt;HTMLInputElement | 空&gt;(空)`。对于大多数情况下使用的 React 管理的 DOM 节点来说,后者是更好的选择。React 将节点存储在 ref 本身中,您不想摸索着更改这些值。 (2认同)
  • 这应该是最重要的答案,因为添加了钩子的使用 (2认同)

bas*_*rat 26

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

refs: {
    [string: string]: any;
    stepInput:any;
}
Run Code Online (Sandbox Code Playgroud)

那么你甚至可以将它包装在一个更好的getter函数中(例如这里):

stepInput = (): HTMLInputElement => ReactDOM.findDOMNode(this.refs.stepInput);
Run Code Online (Sandbox Code Playgroud)

  • 显然“any”在这里不是强制性的。我看到的大多数示例都使用“HTMLInputElement”。只是说明显而易见的事情,但如果您的引用位于 React 组件(即“PeoplePicker”)上,您可以使用该组件作为获取类型的类型。 (2认同)

Jul*_*oux 19

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

const myRef = React.useRef<HTMLDivElement>(null);
Run Code Online (Sandbox Code Playgroud)

并像下面这样使用它:

return <div ref={myRef} />;
Run Code Online (Sandbox Code Playgroud)

  • 谢谢。对于遇到此问题的任何人来说,另一个提示是检查元素。此示例涉及 DIV 元素的使用。例如,表单将使用 - const formRef = React.useRef&lt;HTMLFormElement&gt;(null); (5认同)

Aks*_*tel 17

编辑:这不再是使用Typescript的refs的正确方法.看看杰夫鲍文的答案,并提出它以提高其知名度.

找到了问题的答案.在课堂上使用如下所示的refs.

refs: {
    [key: string]: (Element);
    stepInput: (HTMLInputElement);
}
Run Code Online (Sandbox Code Playgroud)

感谢@basarat指向正确的方向.

  • 我仍然在类型'{[key:string]:组件<any,any> |上不存在`Property'tempInput' 元件; '',当试图访问`this.refs.stepInput`时. (2认同)

api*_*art 16

由于React 16.3添加引用的方法是使用React.createRef,因为Jeff Bowen在他的回答中指出.但是,您可以利用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} />;
    }
}
Run Code Online (Sandbox Code Playgroud)

通过这样做,当您想要使用该引用时,您可以访问所有输入方法:

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

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

private componentRef: React.RefObject<React.Component<IProps>>;
Run Code Online (Sandbox Code Playgroud)

然后,例如,访问道具:

this.componentRef.current.props; // 'props' satisfy IProps interface
Run Code Online (Sandbox Code Playgroud)


小智 6

FIRST ADD AN IMPORT

import React, { useRef } from "react";
Run Code Online (Sandbox Code Playgroud)

那么这个

const studentCapacityRef = useRef<HTMLInputElement>(null);
Run Code Online (Sandbox Code Playgroud)

或这个

const studentCapacityRef = useRef<HTMLAreaElement>(null);
Run Code Online (Sandbox Code Playgroud)

或这个

const studentCapacityRef = useRef<HTMLDivElement>(null);
Run Code Online (Sandbox Code Playgroud)

ETC...