J'utilise TypeScript avec React. J'ai du mal à comprendre comment utiliser les références pour obtenir un typage statique et un intellisense par rapport aux noeuds de réaction référencés par les références. Mon code est comme suit.
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>
);
}}
Si vous utilisez React 16.3+, la méthode suggérée pour créer des réfs utilise 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} />;
}
}
Lorsque le composant est monté, la propriété ref
de l'attribut current
est affectée à l'élément composant/DOM référencé, puis de nouveau à null
lors de son démontage. Ainsi, par exemple, vous pouvez y accéder en utilisant this.stepInput.current
.
Pour plus d'informations sur RefObject
, voir la réponse de @ apieceofbart ou le PRcreateRef()
a été ajouté à.
Si vous utilisez une version antérieure de React (<16.3) ou si vous avez besoin d'un contrôle plus fin lorsque les références sont définies et non définies, vous pouvez utiliser "références de rappel" .
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} />
}
}
Lorsque le composant sera monté, React appellera le callback ref
avec l'élément DOM et l'appelera avec null
lorsqu'il sera démonté. Ainsi, par exemple, vous pouvez y accéder simplement en utilisant this.stepInput
.
En définissant le callback ref
comme une méthode liée sur la classe, par opposition à une fonction inline (comme dans une version précédente de cette réponse), vous pouvez éviter le rappel se faire appeler deux fois lors de mises à jour .
Il y avait une API dans laquelle l'attribut ref
était une chaîne (voir la réponse de d'Akshar Patel ), mais due à certains problèmes , les références de chaîne sont fortement déconseillées et seront éventuellement supprimées.
Édité le 22 mai 2018 pour ajouter la nouvelle façon de faire les références dans React 16.3. Merci à @apieceofbart d’avoir fait remarquer qu’il existait un nouveau moyen
EDIT: Ce n'est plus la bonne façon d'utiliser les références avec TypeScript. Regardez la réponse de Jeff Bowen et augmentez sa participation pour augmenter sa visibilité.
Trouvé la réponse au problème. Utilisez les références comme ci-dessous dans la classe.
refs: {
[key: string]: (Element);
stepInput: (HTMLInputElement);
}
Merci @basarat pour avoir indiqué la bonne direction.
Depuis React16.3, la manière d’ajouter des références consiste à utiliser React.createRef comme l’a souligné Jeff Bowen dans sa réponse. Cependant, vous pouvez tirer parti de TypeScript pour mieux taper votre ref.
Dans votre exemple, vous utilisez ref sur élément d'entrée. Donc, comme je le ferais,
class SomeComponent extends React.Component<IProps, IState> {
private inputRef: React.RefObject<HTMLInputElement>;
constructor() {
...
this.inputRef = React.createRef();
}
...
render() {
<input type="text" ref={this.inputRef} />;
}
}
En faisant cela, lorsque vous souhaitez utiliser cette référence, vous avez accès à toutes les méthodes de saisie:
someMethod() {
this.inputRef.current.focus(); // 'current' is input node, autocompletion, yay!
}
Vous pouvez également l'utiliser sur des composants personnalisés:
private componentRef: React.RefObject<React.Component<IProps>>;
et ensuite, par exemple, avoir accès à des accessoires:
this.componentRef.current.props; // 'props' satisfy IProps interface
Pour utiliser le style de rappel ( https://facebook.github.io/react/docs/refs-and-the-dom.html ) comme recommandé dans la documentation de React, vous pouvez ajouter la définition d'une propriété. sur la classe:
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; }}/>)
}
En l'absence d'un exemple complet, voici mon petit script de test permettant d'obtenir les entrées de l'utilisateur lorsqu'il travaille avec React et TypeScript. Basé en partie sur les autres commentaires et ce lien https://medium.com/@basarat/strongly-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 });
}
});
}
}
Si vous ne voulez pas transférer votre ref
, dans l'interface des accessoires, vous devez utiliser le type RefObject<CmpType>
de import React, { RefObject } from 'react';
Je fais toujours ça, dans ce cas pour prendre un arbitre
let input: HTMLInputElement = ReactDOM.findDOMNode<HTMLInputElement>(this.refs.input);
De React définition du type
type ReactInstance = Component<any, any> | Element;
....
refs: {
[key: string]: ReactInstance
};
Vous pouvez donc accéder à votre élément refs comme suit
stepInput = () => ReactDOM.findDOMNode(this.refs['stepInput']);
sans redéfinition de l'index de référence.
Comme @manakor l'a mentionné, vous pouvez obtenir une erreur comme
La propriété 'stepInput' n'existe pas sur le type '{[clé: chaîne]]: Composant | Élément; }
si vous redéfinissez les références (dépend de IDE et de la version que vous utilisez)
Pour l'utilisateur TypeScript, aucun constructeur n'est requis.
...
private divRef: HTMLDivElement | null = null
getDivRef = (ref: HTMLDivElement | null): void => {
this.divRef = ref
}
render() {
return <div ref={this.getDivRef} />
}
...
Juste pour ajouter une approche différente - vous pouvez simplement lancer votre ref, quelque chose comme:
let myInputElement: Element = this.refs["myInput"] as Element