Я новичок в использовании классов ES6 с React, ранее я привязывал свои методы к текущему объекту (показать в первом примере), но ES6 позволяет мне постоянно привязывать функцию класса к экземпляру класса со стрелками? (Полезно при передаче в качестве функции обратного вызова.) Я получаю ошибки, когда я пытаюсь использовать их, как вы можете, с помощью CoffeeScript:
class SomeClass extends React.Component {
// Instead of this
constructor(){
this.handleInputChange = this.handleInputChange.bind(this)
}
// Can I somehow do this? Am i just getting the syntax wrong?
handleInputChange (val) => {
console.log('selectionMade: ', val);
}
Итак, если бы я должен был передать SomeClass.handleInputChange
, например, setTimeout
, он был бы привязан к экземпляру класса, а не к объекту window
.
Ваш синтаксис слегка выключен, просто отсутствует знак равенства после имени свойства.
class SomeClass extends React.Component {
handleInputChange = (val) => {
console.log('selectionMade: ', val);
}
}
Это экспериментальная функция. Вам нужно будет включить экспериментальные функции в Babel, чтобы получить это для компиляции. Здесь - демонстрация с включенной экспериментальной версией.
Чтобы использовать экспериментальные функции в babel, вы можете установить соответствующий плагин из здесь. Для этой конкретной функции вам нужен плагин transform-class-properties
:
{
"plugins": [
"transform-class-properties"
]
}
Подробнее о предложении для полей классов и статических свойств вы можете прочитать здесь
=
at handleInputChange =
Нет, если вы хотите создать связанные, специфичные для экземпляра методы, вам нужно будет сделать это в конструкторе. Однако для этого вы можете использовать функции стрелок, вместо использования .bind
по прототипу метода:
class SomeClass extends React.Component {
constructor() {
super();
this.handleInputChange = (val) => {
console.log('selectionMade: ', val, this);
};
…
}
}
Существует предложение , которое может позволить вам опустить constructor()
и напрямую помещать присвоение в область класса с той же функциональностью, но я бы не рекомендовал использовать это как очень экспериментальное.
В качестве альтернативы вы всегда можете использовать .bind
, что позволяет объявить метод на прототипе, а затем привязать его к экземпляру в конструктор. Этот подход имеет большую гибкость, поскольку он позволяет модифицировать метод извне вашего класса.
class SomeClass extends React.Component {
constructor() {
super();
this.handleInputChange = this.handleInputChange.bind(this);
…
}
handleInputChange(val) {
console.log('selectionMade: ', val, this);
}
}
bind
незначительно медленнее, чем замыкания, потому что для этого требуется дополнительная уборка. В любом случае функции со стрелками более идиоматичны, начиная с ES6, что должно быть достаточным основанием для их использования.
Я знаю, что этот вопрос был достаточно отвечен, но у меня есть небольшой вклад (для тех, кто не хочет использовать экспериментальную функцию). Из-за проблемы с необходимостью связывать множественные связки функций в конструкторе и заставить его выглядеть беспорядочно, я придумал метод утилиты, который после привязки и вызова в конструкторе делает все необходимые привязки методов для вас автоматически.
Предположим, что у меня есть этот класс с конструктором:
//src/components/PetEditor.jsx
import React from 'react';
class PetEditor extends React.Component {
constructor(props){
super(props);
this.state = props.currentPet || {tags:[], photoUrls: []};
this.tagInput = null;
this.htmlNode = null;
this.removeTag = this.removeTag.bind(this);
this.handleChange = this.handleChange.bind(this);
this.modifyState = this.modifyState.bind(this);
this.handleKeyUp = this.handleKeyUp.bind(this);
this.addTag = this.addTag.bind(this);
this.removeTag = this.removeTag.bind(this);
this.savePet = this.savePet.bind(this);
this.addPhotoInput = this.addPhotoInput.bind(this);
this.handleSelect = this.handleSelect.bind(this);
}
...//actual method declarations omitted
}
Это выглядит грязно, не так ли? Теперь я создал этот метод утилиты
//src/utils/index.js
/**
* NB: to use this method, you need to bind it to the object instance calling it
*/
export function bindMethodsToSelf(objClass, otherMethodsToIgnore=[]){
const self = this;
Object.getOwnPropertyNames(objClass.prototype)
.forEach(method => {
//skip constructor, render and any overrides of lifecycle methods
if(method.startsWith('component')
|| method==='constructor'
|| method==='render') return;
//any other methods you don't want bound to self
if(otherMethodsToIgnore.indexOf(method)>-1) return;
//bind all other methods to class instance
self[method] = self[method].bind(self);
});
}
Все, что мне теперь нужно сделать, это импортировать эту утилиту и добавить вызов к моему конструктору, и мне больше не нужно связывать каждый новый метод в конструкторе. Новый конструктор теперь выглядит чистым, например:
//src/components/PetEditor.jsx
import React from 'react';
import { bindMethodsToSelf } from '../utils';
class PetEditor extends React.Component {
constructor(props){
super(props);
this.state = props.currentPet || {tags:[], photoUrls: []};
this.tagInput = null;
this.htmlNode = null;
bindMethodsToSelf.bind(this)(PetEditor);
}
...
}
shouldComponentUpdate
и getSnapshotBeforeUpdate
Вы используете функцию стрелки, а также привязываете ее к конструктору. Поэтому вам не нужно делать привязку при использовании функций стрелок
class SomeClass extends React.Component {
handleInputChange = (val) => {
console.log('selectionMade: ', val);
}
}
ИЛИ вам нужно привязать функцию только в конструкторе, когда вы используете обычную функцию, например, ниже
class SomeClass extends React.Component {
constructor(props){
super(props);
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(val){
console.log('selectionMade: ', val);
}
}
Также не рекомендуется привязывать функцию непосредственно к рендерингу. Он всегда должен быть в конструкторе
Вопрос готов, но я добавлю несколько примеров использования для использования метода ES6 arrow.
Внутри методов обратного вызова:
let arr = [1,2];
let arr1 = arr.map((val,index) => {
return val * 2;
});
или,
let arr1 = arr.map(val => { // if one argument then no need of using ()
return val * 2;
});
Примечание: внутренняя функция обратного вызова, если используется this
, то здесь this
ссылка на функцию обратного вызова вместо класса компонента.
Пример:
arr.map(function(val) {
this.func(val); // Will not work
});
arr.map((val,index)=>{
this.func(); // Will work
});