我正在尝试创建一个能够删除列表中项目的点击事件,但是当我点击它时,我得到“TypeError:无法读取未定义的属性'道具'。”
我试图尽可能地坚持使用ES6,而且我很确定它可以在某个地方绑定“这个”,但我已经尝试了很多地方并且没有成功。
import React, { Component } from 'react';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
<StreetFighter />
</div>
);
}
}
class StreetFighter extends Component {
constructor(props) {
super(props);
this.state = {
characters: [
'Chun-Li',
'Guile',
'Ryu',
'Ken',
'E.Honda',
'Dhalsim',
],
};
}
render() {
let characters = this.state.characters;
characters = characters.map((char, index) => {
return (
<Character char={char} key={index} onDelete={this.onDelete} />
);
});
return (
<div>
<p>Street Fighter Characters</p>
<ul>{characters}</ul>
</div>
);
}
onDelete(chosenCharacter) {
let updatedCharactersList = this.state.characters.filter(
(char, index) => {
return chosenCharacter !== char;
}
);
this.setState({
characters: updatedCharactersList,
});
}
}
class Character extends Component {
render() {
return (
<li>
<div className="character">
<span className="character-name">{this.props.char}</span>
<span
className="character-delete"
onClick={this.handleDelete}
> x </span>
</div>
</li>
)
};
handleDelete() {
this.props.onDelete(this.props.char);
}
}
export default App;
答案 0 :(得分:6)
由于JS OOP系统将类传递给像这样的道具时,你重写了类方法的上下文。因此,为了使其工作,有几种方法:
1)这不太好,因为bind alwaus会返回新函数,即使没有更新道具,你的组件也会重新呈现
import React, { Component } from 'react';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
<StreetFighter />
</div>
);
}
}
class StreetFighter extends Component {
constructor(props) {
super(props);
this.state = {
characters: [
'Chun-Li',
'Guile',
'Ryu',
'Ken',
'E.Honda',
'Dhalsim',
],
};
}
render() {
let characters = this.state.characters;
characters = characters.map((char, index) => {
return (
<Character char={char} key={index} onDelete={this.onDelete.bind(this)} />
);
});
return (
<div>
<p>Street Fighter Characters</p>
<ul>{characters}</ul>
</div>
);
}
onDelete(chosenCharacter) {
let updatedCharactersList = this.state.characters.filter(
(char, index) => {
return chosenCharacter !== char;
}
);
this.setState({
characters: updatedCharactersList,
});
}
}
class Character extends Component {
render() {
return (
<li>
<div className="character">
<span className="character-name">{this.props.char}</span>
<span
className="character-delete"
onClick={this.handleDelete.bind(this)}
> x </span>
</div>
</li>
)
};
handleDelete() {
this.props.onDelete(this.props.char);
}
}
export default App;
2)在我的代码中,我使用箭头函数作为此类情况的类属性(这是我认为最常见的解决方案之一)
class Character extends Component {
render() {
return (
<li>
<div className="character">
<span className="character-name">{this.props.char}</span>
<span
className="character-delete"
onClick={this.handleDelete.bind(this)}
> x </span>
</div>
</li>
)
};
handleDelete = () => {
this.props.onDelete(this.props.char);
}
}
答案 1 :(得分:6)
TLDR:您的鳕鱼中的具体问题在本答案末尾的段落中说明。
这是JavaScript的this
的经典问题,如果你还没有,我建议你稍微阅读一下。
简而言之(不仅适合你,但如果其他人正在阅读本文),JavaScript函数定义(如果不是arrow function)重新定义this
是什么,即它指向的是什么。
所以当你定义:
handleDelete() {
this.props.onDelete(this.props.char);
}
该函数的this
并未指向它所定义的类的对象实例。如果您来自C ++ / C#/ Java背景,这有点违反直觉。问题是this
在类进入JavaScript之前就已经退出了,而且对于带有一堆定义原型的函数来说类不仅仅是语法糖(参见here),或者换句话说它不是默认情况下将其绑定到其函数。
有几种典型的解决方法:
this
绑定到所有函数(在构造函数中)class Character extends Component {
constructor(props) {
super(props)
this.handleDelete = this.handleDelete.bind(this)
}
render() {
// ...
};
handleDelete() {
this.props.onDelete(this.props.char);
}
}
注意:而不是这个你可以在每次使用函数时绑定this
(即onClick={this.handleDelete.bind(this)}
,但是不是建议,因为如果你忘记绑定this
,它会使你的代码容易出错。如果你是链接函数,你可能会在某处指出错误的东西。更不用说{ {1}}是一个函数,在React中,你将在每个渲染上进行函数调用。但是,如果你遇到需要更改的情况,请记住是一件好事。 {1}} 强>
bind
如上所述,在其他答案中,箭头函数不会重新定义this
指针。你在这里有效地做的是将箭头函数分配给该类的对象实例的属性。换句话说,函数(是一个不重新定义class Character extends Component {
render() {
// ...
};
handleDelete = () => {
this.props.onDelete(this.props.char);
}
}
的箭头函数)从外部作用域(类的作用域)中获取this
,但是,因为箭头函数是匿名函数,所以你命名它通过将其分配给name property。
所有其他解决方案都是上述两种解决方案的一些变体
this
和this
都遇到此onDelete
问题。
此外,正如@Alyson Maia所述,您的handleDelete
组件可以写为functional component:
this
答案 2 :(得分:1)
通过使用箭头功能,您可以解决this
上下文。试试这个:
你的onClick事件
onClick={this.handleDelete}
和你的功能定义:
handleDelete = () => {
//here you can access the this.props
}
答案 3 :(得分:1)
当您在this
内使用handleDelete
时,您没有引用该类。您可以使用followwing approches解决此问题
使用无状态组件(在您的情况下最好的方法)
不改变状态的组件,不需要Class
,可以将它们定义为函数或常量
Class Parent extends React.Component {
state = { ... }
onDelete = () => { ... }
render() {
return (
<Child onDelete={this.onDelete} />
)
}
}
function Child(props) {
return (
<button onClick={props.onDelete}>Delete</button>
)
}
使用箭头功能
箭头函数不会在类范围内的箭头函数内定义范围。
Class Parent extends React.Component {
state = { foo: 'bar' }
wrongMethod() {
console.log(this.state) // undefined
}
rightMethod = () => {
console.log(this.state) // { foo: 'bar' }
}
render() {
this.wrongMethod()
this.rightMethod()
return (
<h1>Hello World!</h1>
)
}
}
使用bind
如果你有一个使用this
的方法,你必须将方法范围绑定到类范围,这可以像下面这样做。由于每次渲染都会调用bindOnRender
并在每次调用时创建一个新函数,因此Class Parent extends React.Component {
constructor() {
this.state = { foo: 'bar' }
this.bindOnConstructor.bind(this)
}
bindOnConstructor() {
console.log(this.state) // { foo: 'bar' }
}
bindOnRender = () => {
console.log(this.state) // { foo: 'bar' }
}
render() {
return (
<button onClick={this.bindOnConstructor}>Foo</button>
<button onClick={this.bindOnRender.bind(this)}>Bar</button>
)
}
}
会出现性能问题。
nyc.domain.com => domain.com/daughter.php?d=nyc
washington.domain.com => domain.com/daughter.php?d=washington
...
答案 4 :(得分:1)
创建用于处理事件的函数时,请不要忘记通过构造函数将其添加到道具中,如下所示:
constructor (props) {
super(props)
this.yourFunction = this.yourFunction.bind(this)
}