reactjs - starter - Cómo usar referencias en React with Typecript
react with typescript or not (12)
Estoy usando Typecript con React. Tengo problemas para entender cómo usar las referencias para obtener un tipeo estático e inteligencia con respecto a los nodos de reacción a los que hacen referencia las referencias. Mi código es el siguiente.
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>
);
}}
A falta de un ejemplo completo, aquí está mi pequeño script de prueba para obtener la entrada del usuario cuando trabaja con React y TypeScript. Basado parcialmente en los otros comentarios y este enlace 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 });
}
});
}
}
De la definición de tipo React
type ReactInstance = Component<any, any> | Element;
....
refs: {
[key: string]: ReactInstance
};
Para que pueda acceder a su elemento de referencia de la siguiente manera
stepInput = () => ReactDOM.findDOMNode(this.refs[''stepInput'']);
sin redefinir el índice de referencia.
Como @manakor mencionó, puede obtener un error como
La propiedad ''stepInput'' no existe en el tipo ''{[clave: cadena]: Componente | Elemento; }
si redefine las referencias (depende del IDE y la versión de TS que use)
Desde React 16.3, la forma de agregar referencias es usar React.createRef como Jeff Bowen señaló en su respuesta. Sin embargo, puede aprovechar Typecript para escribir mejor su referencia.
En su ejemplo, está utilizando ref en el elemento de entrada. Entonces, la forma en que lo haría es:
class SomeComponent extends React.Component<IProps, IState> {
private inputRef: React.RefObject<HTMLInputElement>;
constructor() {
...
this.inputRef = React.createRef();
}
...
render() {
<input type="text" ref={this.inputRef} />;
}
}
Al hacer esto cuando desea hacer uso de esa referencia, tiene acceso a todos los métodos de entrada:
someMethod() {
this.inputRef.current.focus(); // ''current'' is input node, autocompletion, yay!
}
También puede usarlo en componentes personalizados:
private componentRef: React.RefObject<React.Component<IProps>>;
y luego tener, por ejemplo, acceso a accesorios:
this.componentRef.current.props; // ''props'' satisfy IProps interface
Para el usuario mecanografiado no se requiere constructor.
...
private divRef: HTMLDivElement | null = null
getDivRef = (ref: HTMLDivElement | null): void => {
this.divRef = ref
}
render() {
return <div ref={this.getDivRef} />
}
...
Para usar el estilo de devolución de llamada ( https://facebook.github.io/react/docs/refs-and-the-dom.html ) como se recomienda en la documentación de React, puede agregar una definición para una propiedad en la clase:
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; }}/>)
}
Si no va a reenviar su
ref
, en la interfaz de Props debe usar el tipo
RefObject<CmpType>
de
import React, { RefObject } from ''react'';
Si usa React 16.3+, la
forma sugerida
de crear referencias es usando
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} />;
}
}
Cuando el componente se monta, la propiedad
current
del atributo
ref
se asignará al componente / elemento DOM referenciado y se asignará nuevamente a
null
cuando se desmonte.
Entonces, por ejemplo, puede acceder usando
this.stepInput.current
.
Para obtener más información sobre
RefObject
, consulte
la respuesta de @ apieceofbart
o se agregó
PR
createRef()
.
Si está utilizando una versión anterior de React (<16.3) o necesita un control más detallado sobre cuándo las referencias están configuradas y no, puede usar "referencias de devolución de llamada" .
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} />
}
}
Cuando el componente se monta, React llamará a la devolución de llamada de
ref
con el elemento DOM y lo llamará con
null
cuando se desmonte.
Entonces, por ejemplo, puede acceder a él simplemente usando
this.stepInput
.
Al definir la devolución de llamada de
ref
como un método enlazado en la clase en lugar de una función en línea (como en una
versión anterior
de esta respuesta), puede evitar que la devolución de llamada
se llame dos veces durante las
actualizaciones.
Solía haber
una API donde el atributo de
ref
era una cadena (ver
la respuesta de Akshar Patel
), pero debido a
some
issues
, las referencias de cadena se desaconsejan y eventualmente se eliminarán.
Editado el 22 de mayo de 2018 para agregar la nueva forma de hacer referencias en React 16.3. Gracias @apieceofbart por señalar que había una nueva forma.
Siempre hago esto, en ese caso para tomar una referencia
let input: HTMLInputElement = ReactDOM.findDOMNode<HTMLInputElement>(this.refs.input);
Solo para agregar un enfoque diferente: simplemente puede emitir su referencia, algo como:
let myInputElement: Element = this.refs["myInput"] as Element
Una forma (que he estado haciendo ) es configurarlo manualmente:
refs: {
[string: string]: any;
stepInput:any;
}
entonces incluso puede envolver esto en una función getter más agradable (por ejemplo, here ):
stepInput = (): HTMLInputElement => ReactDOM.findDOMNode(this.refs.stepInput);
EDITAR: Esta ya no es la forma correcta de usar referencias con Typecript. Mira la respuesta de Jeff Bowen y vota para aumentar su visibilidad.
Encontré la respuesta al problema. Use referencias como se muestra a continuación dentro de la clase.
refs: {
[key: string]: (Element);
stepInput: (HTMLInputElement);
}
Gracias @basarat por apuntar en la dirección correcta.
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();
}
}
ponerlos en un objeto