我使用Typescript与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>
    );
}}

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

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

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

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

编辑:这不再是在Typescript中使用refs的正确方式。看看杰夫·鲍恩的回答,给它点赞,以提高它的曝光度。

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

refs: {
    [key: string]: (Element);
    stepInput: (HTMLInputElement);
}

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


由于缺乏完整的示例,下面是我的小测试脚本,用于在使用React和TypeScript时获取用户输入。部分基于其他评论和此链接https://medium.com/@basarat/strong -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 });
        }
    });
}

}


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

把它们放在一个对象中


来自React类型定义

    type ReactInstance = Component<any, any> | Element;
....
    refs: {
            [key: string]: ReactInstance
    };

你可以像下面这样访问你的refs元素

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

没有重新定义refs索引。

正如@manakor提到的,你可能会得到这样的错误

属性“stepInput”在类型“{[key: string]”上不存在: 组件|元素;}

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


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

只是添加一个不同的方法-你可以简单地强制转换你的引用,像这样:

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

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

输入:htmlinterment =反应。


如果你使用的是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属性的当前属性将被赋值给被引用的组件/DOM元素,并在卸载时赋值回null。例如,你可以使用this。stepput。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将使用DOM元素调用ref回调,并在卸载时使用null调用它。例如,你可以简单地使用this.stepInput访问它。

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


曾经有一个API,其中ref属性是一个字符串(参见Akshar Patel的答案),但由于一些问题,字符串引用是强烈反对的,最终将被删除。


编辑于2018年5月22日,在React 16.3中添加了新的裁判方式。感谢@apieceofbart指出了一种新方法。


从React 16.3开始,添加refs的方法就是使用React。正如Jeff Bowen在回答中指出的那样,createRef。然而,你可以利用Typescript来更好地输入你的引用。

在你的例子中,你在input元素上使用了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>>;

然后,例如,获得道具:

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

对于typescript用户,不需要构造函数。

...

private divRef: HTMLDivElement | null = null

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

render() {
    return <div ref={this.getDivRef} />
}

...


如果你不想转发你的ref,在Props界面你需要使用RefObject<CmpType>类型从import React, {RefObject}从' React ';


如果你在使用React。FC,添加HTMLDivElement接口:

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

然后像下面这样使用它:

return <div ref={myRef} />;

当你有一个元素数组的时候,你可以这样做:

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

反应。createRef(类比较)

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

反应。useRef(钩子/函数比较)

a) Use readonly refs for React-managed DOM nodes:
const FunctionApp = () => {
  // note the passed-in `null` arg ----------------v
  const inputRef = React.useRef<HTMLInputElement>(null)
  return <input type="text" ref={inputRef} />
}

inputRef。通过将Current属性的值初始化为null, Current属性变为只读属性。

b) Use

可变参

for arbitrary stored values akin to instance variables:
const FunctionApp = () => {
  const renderCountRef = useRef(0)
  useEffect(() => {
    renderCountRef.current += 1
  })
  // ... other render code
}

注意:在这种情况下不要初始化useRef为null——它会使renderCountRef类型为只读(参见示例)。如果你需要提供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} />
}

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

操场上的样品


首先添加一个导入

import React, { useRef } from "react";

那么这个

const studentCapacityRef = useRef<HTMLInputElement>(null);

或者这个

const studentCapacityRef = useRef<HTMLAreaElement>(null);

或者这个

const studentCapacityRef = useRef<HTMLDivElement>(null);

等等……