Как использовать функции стрелки (открытые поля класса) в качестве методов класса?
Я новичок в использовании классов 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
to, например setTimeout
, он будет ограничен экземпляром класса, а не window
объект.
4 ответа:
ваш синтаксис немного офф, просто отсутствует знак равенства после имени свойства.
class SomeClass extends React.Component { handleInputChange = (val) => { console.log('selectionMade: ', val); } }
это экспериментальная функция. Вам нужно будет включить экспериментальные функции в Babel, чтобы получить это для компиляции. здесь это демо с экспериментальным включен.
для использования экспериментальных функций в babel вы можете установить соответствующий плагин из здесь. Для этой конкретной функции вам нужно
transform-class-properties
плагин:{ "plugins": [ "transform-class-properties" ] }
вы можете прочитать больше о предложении для полей класса и статических свойств здесь
нет, если вы хотите создать привязанные, специфические для экземпляра методы, вам придется сделать это в конструкторе. Однако для этого можно использовать функции стрелок, а не использовать
.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); } }
Я знаю, что на этот вопрос был достаточно дан ответ, но у меня просто есть небольшой вклад (для тех, кто не хочет использовать экспериментальную функцию). Из-за проблемы привязки нескольких Привязок функций в конструкторе и создания беспорядка, я придумал служебный метод, который после привязки и вызова в конструкторе автоматически выполняет все необходимые привязки методов для вас.
Предположим, у меня есть этот класс с конструктор:
//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); } ... }
вы используете функцию стрелки, а также связываете ее в конструкторе. Так что вам не нужно делать привязку, когда вы используете функции стрелки
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); } }
также не рекомендуется связывать функцию непосредственно в рендере. Он всегда должен быть в конструкторе