react event actualizar javascript reactjs ecmascript-6

javascript - event - react setstate



¿Por qué tengo que.bind(this) para los métodos definidos en la clase de componente React, pero no en la clase ES6 normal (5)

Algo que me desconcierta es por qué cuando defino una clase de componente de reacción, los valores contenidos en this objeto no están definidos en los métodos definidos ( this está disponible en los métodos de ciclo de vida) dentro de la clase a menos que use .bind(this) o defina el método usando una función de flecha, por ejemplo, en el siguiente código this.state no estará definido en la función renderElements porque no la renderElements con una función de flecha y no .bind(this)

class MyComponent extends React.Component { constructor() { super(); this.state = { elements: 5 } } renderElements() { const output = []; // In the following this.state.elements will be undefined // because I have not used .bind(this) on this method in the constructor // example: this.renderElements = this.renderElements.bind(this) for(let i = 0; i < this.state.elements; i ++){ output.push(<div key={i} />); } return output; } // .this is defined inside of the lifecycle methods and // therefore do not need call .bind(this) on the render method. render() { return ( <div onClick={this.renderElements}></div> ); } }

Luego, en el siguiente ejemplo, no necesito usar .bind(this) o una función de flecha, está disponible como se esperaba en la función speak

class Animal { constructor(name) { this.name = name; } speak() { console.log(this.name + '' makes a noise.''); } } class Dog extends Animal { speak() { console.log(this.name + '' barks.''); } } var d = new Dog(''Mitzie''); d.speak();

http://jsbin.com/cadoduxuye/edit?js,console

Para aclarar, mi pregunta es de dos partes. Uno) por qué en el segundo ejemplo de código no necesito llamar a .bind(this) a la función speak , pero sí en el componente React para la función renderElements y Two) por qué los métodos de ciclo de vida (render, componentDidMount, etc.) ya tiene acceso a la clase '' this objeto, pero renderElements no.

En los documentos React dice lo siguiente

[React Component Class] Los métodos siguen la misma semántica que las clases ES6 normales, lo que significa que no vinculan esto automáticamente a la instancia.

Pero claramente lo hacen, como lo muestra el segundo ejemplo de código que publiqué.

Actualizar

Ambos enlaces en los primeros dos comentarios muestran un ejemplo de funcionamiento de las clases React que NO usan .bind(this) en los métodos de clase y funciona bien. Pero aún en los documentos se dice explícitamente que debe vincular sus métodos o usar una función de flecha. En un proyecto usando gulp y babel puedo reproducir. ¿Podría significar que los navegadores han actualizado las cosas?

Actualización 2

Mi ejemplo de código inicial tenía this.renderElements() llamado directamente en la función de representación. Eso funcionaría como se esperaba sin vincular la función o definirla con una función de flecha. El problema ocurre cuando pongo la función como un controlador onClick .

Actualización 3

El problema ocurre cuando pongo la función como un controlador onClick .

De hecho, no es un problema en absoluto. El contexto de this cambia cuando se pasa al controlador onClick, así que así es como funciona JS.


1. Funciones de flecha:

Una expresión de función de flecha tiene una sintaxis más corta en comparación con las expresiones de función y enlaza léxicamente el valor this ( does not bind its own this, arguments, super, or new.target ). Las funciones de flecha son siempre anonymous . Estas expresiones de función son más adecuadas para funciones que no son de método y no pueden usarse como constructores .

Function.prototype.bind():

El método bind () crea una nueva función que, cuando se llama, tiene esta palabra clave establecida en el valor proporcionado, con una secuencia dada de argumentos que precede a cualquier proporcionada cuando se llama a la nueva función.

2. Especificaciones de componentes y ciclo de vida

Para ser absolutamente claro: la mayoría de los métodos de ciclo de vida no están vinculados, sino que se invocan en una instancia utilizando la notación de puntos (verdadero para componentWillMount , componentWillUnmount , componentWillReceiveProps y así sucesivamente ...), excepto componentDidMount que está vinculado a la instancia ya que se pone en cola en la transacción.


El valor de this depende principalmente de cómo se llama la función. Dado d.speak(); , this se referirá a d porque la función se llama como un "método de objeto".

Pero en <div>{this.renderElements}</div> no estás llamando a la función. Estás pasando la función a React que lo llamará de alguna manera. Cuando se llama, React no sabe a qué objeto pertenecía la función, por lo que no puede establecer el valor correcto para this . La unión resuelve eso

De hecho, creo que lo que realmente quieres es

<div>{this.renderElements()}</div> // call function ^^

es decir, llamar a la función como un método de objeto. Entonces no tienes que atarlo.

Echa un vistazo a MDN para aprender más sobre this .


Los controladores de eventos en el componente no se vincularán automáticamente a la instancia del componente como otros métodos (métodos de ciclo de vida ...).

class MyComponent extends React.Component { render(){ return ( <div onClick={this.renderElements}> {this.renderElements()} <-- `this` is still in side the MyComponent context </div> ) } } //under the hood var instance = new MyComponent(); var element = instance.render(); //click on div element.onClick() <-- `this` inside renderElements refers to the window object now

Mira este ejemplo para entender this más:

class Animal { constructor(name) { this.name = name; } speak() { console.log(this.name + '' makes a noise.''); } } class Dog extends Animal { run(){ console.log(this.name + '' runs''); } speak() { console.log(this.name + '' barks.''); this.run(); <-- `this` is still in the Dog context return {onRun : this.run}; } } var d = new Dog(''Mitzie''); var myDog = d.speak(); myDog.onRun() <-- `this` is now in the global context which is the `window` object

Puedes consultar este article para más información.


Solo pon siempre el autoBind(this); codifique en su constructor y nunca se preocupe por los punteros de método.

npm install --save auto-bind-inheritance

const autoBind = require(''auto-bind-inheritance''); class Animal { constructor(name) { autoBind(this); this.name = name; } printName() { console.log(this.name); } ... } let m = new Animal(''dog''); let mpntr = m.printName; m.printName() //> ''dog'' mpntr() //> ''dog'', because auto-bind, binds ''this'' to the method.


Funciones en las clases de ES6 : el caso lo explica muy bien @Felix Kling. Cada vez que llama a una función en un objeto, this apunta al objeto.

Métodos de ciclo de vida en React.Component : cada vez que React crea una instancia de su componente como myComponent = new MyComponent() sabe en qué objeto invocar los métodos de ciclo de vida, es decir, myComponent . Por lo tanto, una simple llamada myComponent.componentDidUpdate() hace que esté disponible en el método del ciclo de vida de componentDidUpdate . Lo mismo para los otros métodos de ciclo de vida.

Handlers & Bound en React.Component - this.state undefined está undefined , porque this realidad es una window : this.state y vea. La razón es que React invoca manejadores en el contexto global, a menos que tenga el manejador vinculado a otro contexto que anule la window (vea también la respuesta de @Phi Nguyen). Creo que lo han hecho para permitirle una mayor flexibilidad, porque en aplicaciones complejas su controlador puede provenir de otro componente pasado por accesorios y luego le gustaría tener la posibilidad de decir: "Oye, reacciona, this no es mi componente, pero es padre ".

La documentación de React es una oferta engañosa cuando dice

Los métodos siguen la misma semántica que las clases ES6 normales, lo que significa que no vinculan esto automáticamente a la instancia.

Lo que quieren decir es que

var dog = new Dog(''Mitzie''); speak = d.speak; dog.speak() // this will be dog, because the function is called on dog speak() // this will be window, and not dog, because the function is not bound