React: "this" undefined внутри функции компонента
class PlayerControls extends React.Component {
constructor(props) {
super(props)
this.state = {
loopActive: false,
shuffleActive: false,
}
}
render() {
var shuffleClassName = this.state.toggleActive ? "player-control-icon active" : "player-control-icon"
return (
<div className="player-controls">
<FontAwesome
className="player-control-icon"
name='refresh'
onClick={this.onToggleLoop}
spin={this.state.loopActive}
/>
<FontAwesome
className={shuffleClassName}
name='random'
onClick={this.onToggleShuffle}
/>
</div>
);
}
onToggleLoop(event) {
// "this is undefined??" <--- here
this.setState({loopActive: !this.state.loopActive})
this.props.onToggleLoop()
}
Я хочу обновить состояние loopActive
при переключении, но this
объект undefined в обработчике. Согласно учебному документу, я this
должен ссылаться на компонент. Я что-то пропустил?
Ответы
Ответ 1
ES6 React.Component не привязывает методы автоматически к себе. Вы должны связать их сами в конструкторе. Как это:
constructor (props){
super(props);
this.state = {
loopActive: false,
shuffleActive: false,
};
this.onToggleLoop = this.onToggleLoop.bind(this);
}
Ответ 2
Есть несколько способов.
Один из них - добавить
this.onToggleLoop = this.onToggleLoop.bind(this);
в конструкторе.
Другая функция стрелок
onToggleLoop = (event) => {...}
.
И тогда есть onClick={this.onToggleLoop.bind(this)}
.
Ответ 3
Напишите свою функцию следующим образом:
onToggleLoop = (event) => {
this.setState({loopActive: !this.state.loopActive})
this.props.onToggleLoop()
}
Функции Fat Arrow
привязка для ключевого слова this одинакова снаружи и внутри функции жирной стрелки. Это отличается от функций, объявленных с функцией, которая может связать это с другим объектом при вызове. Поддержание привязки this очень удобно для таких операций, как сопоставление: this.items.map(x => this.doSomethingWith(x)).
Ответ 4
Я столкнулся с подобным связыванием в функции рендеринга и в итоге передал контекст this
следующим образом:
{someList.map(function(listItem) {
// your code
}, this)}
Я также использовал:
{someList.map((listItem, index) =>
<div onClick={this.someFunction.bind(this, listItem)} />
)}
Ответ 5
Если вы используете babel, вы связываете это с помощью оператора привязки ES7
https://babeljs.io/docs/en/babel-plugin-transform-function-bind#auto-self-binding
export default class SignupPage extends React.Component {
constructor(props) {
super(props);
}
handleSubmit(e) {
e.preventDefault();
const data = {
email: this.refs.email.value,
}
}
render() {
const {errors} = this.props;
return (
<div className="view-container registrations new">
<main>
<form id="sign_up_form" onSubmit={::this.handleSubmit}>
<div className="field">
<input ref="email" id="user_email" type="email" placeholder="Email" />
</div>
<div className="field">
<input ref="password" id="user_password" type="new-password" placeholder="Password" />
</div>
<button type="submit">Sign up</button>
</form>
</main>
</div>
)
}
}
Ответ 6
Вы должны заметить, что this
зависит от того, как вызывается функция
То есть: когда функция вызывается как метод объекта, ее this
устанавливается на объект, к которому вызывается метод.
this
доступен в контексте JSX в качестве объекта компонента, поэтому вы можете вызывать нужный метод встроенным методом this
.
Если вы просто передадите ссылку на функцию/метод, кажется, что реакция будет вызывать ее как независимую функцию.
onClick={this.onToggleLoop} // Here you just passing reference, React will invoke it as independent function and this will be undefined
onClick={()=>this.onToggleLoop()} // Here you invoking your desired function as method of this, and this in that function will be set to object from that function is called ie: your component object
Ответ 7
Если вы вызываете ваш созданный метод в методах жизненного цикла, таких как componentDidMount... тогда вы можете использовать только this.onToggleLoop = this.onToogleLoop.bind(this)
и функцию стрелки жира onToggleLoop = (event) => {...}
.
Нормальный подход объявления функции в конструкторе не работает, потому что методы жизненного цикла называются ранее.