如何在 React 和 Typescript 中使用 refs

IT技术 reactjs typescript
2021-04-18 01:41:00

我在 React 中使用 Typescript。我无法理解如何使用 refs 来获得关于 refs 引用的react节点的静态类型和智能感知。我的代码如下。

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>
    );
}}
6个回答

如果您使用的是 React 16.3+,建议的创建 refs 的方法是使用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) 或需要更细粒度地控制何时设置和取消设置 refs,则可以使用“回调 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 将ref使用 DOM 元素调用回调,并null在卸载时调用它因此,例如,您只需使用this.stepInput.

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


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


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

请注意,这是首选方式。下面带有refsclass 属性的示例将在即将推出的 React 版本中弃用。
2021-06-02 01:41:00
我只是在你的答案中没有看到任何关于typescript的内容,我会添加另一个答案
2021-06-10 01:41:00
请注意,这已经是一种老方法了:) 当前是使用 React.createRef()
2021-06-13 01:41:00
你也可以使用 React.RefObject<HTMLElement>
2021-06-16 01:41:00
@apieceofbart 感谢您的提醒。更新了答案以包含新方法。
2021-06-19 01:41:00

React.createRef (class)

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

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

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

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

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

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

回调引用(两者)

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

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

游乐场示例

这应该是最重要的答案,因为添加了钩子的使用
2021-06-07 01:41:00
它传递了null我缺少的初始值,谢谢!
2021-06-08 01:41:00
什么之间的区别useRef() as MutableRefObject<HTMLInputElement>useRef<HTMLInputElement>(null)
2021-06-14 01:41:00
好问题 - 的current属性MutableRefObject<HTMLInputElement>可以修改,而useRef<HTMLInputElement>(null)创建一个标记为RefObject类型如果您需要自己更改 refs 中的当前 DOM 节点,例如与外部库结合使用,则可以使用前者。也可以不写: 大多数情况下,后者是 React 托管 DOM 节点的更好选择。React 将节点存储在 refs 本身中,您不想在更改这些值时摸索。currentreadonlyasuseRef<HTMLInputElement | null>(null)
2021-06-15 01:41:00

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

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

然后你甚至可以用一个更好的 getter 函数来包装它(例如这里):

stepInput = (): HTMLInputElement => ReactDOM.findDOMNode(this.refs.stepInput);
显然any这里不是强制性的。我看到的大多数示例都使用HTMLInputElement. 只是说明很明显,但是如果您的 ref 位于 React 组件(即PeoplePicker)上,您可以使用该组件作为获取类型的类型。
2021-05-29 01:41:00
谢谢@basarat。我尝试了您的解决方案,但出现此错误“类型元素不可分配给类型”HTMLInputElement。元素类型中缺少属性接受''
2021-06-18 01:41:00
可能是较新版本的 react-dom 定义的问题。同时用作断言
2021-06-18 01:41:00

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

在您的示例中,您在输入元素上使用 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} />;
    }
}

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

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

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

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

然后,例如,可以访问 props :

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

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

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

并像下面这样使用它:

return <div ref={myRef} />;
谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢。谢谢你。
2021-05-23 01:41:00
谢谢。对于遇到此问题的任何人的另一个提示是检查元素。此示例指的是 DIV 元素的使用。例如,表单将使用 - const formRef = React.useRef<HTMLFormElement>(null);
2021-06-19 01:41:00