[英]React - TypeError: Cannot read property 'props' of undefined
I'm trying to create a click event be able to delete an item on my list, but when I click it I get "TypeError: Cannot read property 'props' of undefined".我正在尝试创建一个能够删除我列表中的项目的点击事件,但是当我点击它时,我得到“类型错误:无法读取未定义的属性‘道具’”。
I'm trying to stick to ES6 as much as possible, and I'm pretty sure its something to do binding 'this' somewhere, but I've tried many places and been unsuccessful.我试图尽可能地坚持使用 ES6,而且我很确定它可以在某处绑定“this”,但是我尝试了很多地方都没有成功。
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;
TLDR: The specific problem in your cod is stated in the paragraph near the end of this answer. TLDR:您的鳕鱼中的具体问题在本答案末尾附近的段落中有所说明。
This is a classical problem with JavaScript's this
, I suggest you read a little bit into it if you haven't already.这是 JavaScript 的
this
一个经典问题,如果您还没有读过,我建议您阅读一下。
To put it in short and simpler terms (not just for you, but if someone else is reading this), a JavaScript function definition (if not written as an arrow function ) redefines what this
is, ie what it is pointing to.简而言之(不只是为您,但如果其他人正在阅读此内容),JavaScript 函数定义(如果未编写为箭头函数)重新定义
this
是什么,即它指向什么。 So when you define:所以当你定义:
handleDelete() {
this.props.onDelete(this.props.char);
}
That function's this
is not pointing to the object instance of the class it is defined in. This is a bit counter-intuitive if you're coming from a C++/C#/Java background.该函数的
this
不指向定义它的类的对象实例。如果您来自 C++/C#/Java 背景,这有点违反直觉。 The thing is that this
exited way before classes came into JavaScript and classes are noting more than a syntax sugar for a function with a bunch of defined prototypes (see here ), or in other words it does not bind this to its functions by default.问题是,在类进入 JavaScript 之前,
this
已退出方式,并且类不仅仅是具有一堆已定义原型的函数的语法糖(请参阅此处),或者换句话说,默认情况下它不会将 this 绑定到其函数。
There are a couple typical ways around this:有几种典型的方法可以解决这个问题:
this
to all functions (in the constructor) this
绑定到所有函数(在构造函数中)class Character extends Component {
constructor(props) {
super(props)
this.handleDelete = this.handleDelete.bind(this)
}
render() {
// ...
};
handleDelete() {
this.props.onDelete(this.props.char);
}
}
NOTE: Instead of this you can bind this
on every use of the function (ie onClick={this.handleDelete.bind(this)}
, but it's not advisable because it will make you're code prone to errors if you ever forget to bind this
. Also if you're chaining functions, you might point to the wrong thing somewhere. Not to mention that bind
is a function, and in React you will be making a function call on every render. However, it is a good thing to keep in mind if you ever have a situation in which you have to to change this
.注意:代替这个,你可以在每次使用函数时绑定
this
(即onClick={this.handleDelete.bind(this)}
,但这是不可取的,因为如果你忘记了它会让你的代码容易出错bind this
。另外,如果你在链接函数,你可能会在某处指出错误的东西。更不用说bind
是一个函数,在 React 中你将在每次渲染时进行函数调用。然而,这是一件好事请记住,如果您遇到必须改变this
情况的情况。
class Character extends Component {
render() {
// ...
};
handleDelete = () => {
this.props.onDelete(this.props.char);
}
}
As stated above, and in the other answers, arrow functions do not redefine the this
pointer.如上所述,在其他答案中,箭头函数不会重新定义
this
指针。 What you're effectively doing here is assigning the arrow function to an atribute of the object instance of this class.您在这里有效地做的是将箭头函数分配给此类的对象实例的属性。 In other words the function (being an arrow function that does not redefine
this
) takes the this
from the outer scope (the scope of the class), however, because arrow functions are anonymous functions, you name it by assigning it to a name property .换句话说,函数(作为不重新定义
this
的箭头函数)从外部作用域(类的作用域)获取this
,但是,因为箭头函数是匿名函数,您可以通过将其分配给name 属性来命名它.
All other solutions are some variations of the two above所有其他解决方案都是上述两种解决方案的一些变体
Both onDelete
and handleDelete
suffer from this this
issue. onDelete
和handleDelete
都onDelete
this
问题。
Also, as @Alyson Maia has stated above, your Character
component can be written as a functional component :此外,正如@Alyson Maia上面所说,您的
Character
组件可以编写为功能组件:
const Character = (props) => {
render() {
return (
<li>
<div className="character">
<span className="character-name">{this.props.char}</span>
<span
className="character-delete"
onClick={props.onDelete(props.char)}
> x </span>
</div>
</li>
)
};
}
You rewrite the context of the class method when you pass it to props like this because of JS OOP system.由于 JS OOP 系统,当您像这样将类方法传递给 props 时,您重写了类方法的上下文。 So to make it work there are several approaches:
因此,要使其发挥作用,有几种方法:
1) This is not so good because bind always returns new function and your component will re-render even if there are no updates in props 1) 这不太好,因为 bind 总是返回新函数,即使 props 没有更新,你的组件也会重新渲染
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) In my code I use arrow functions as class properties for such cases (it's one of the most common solutions, I think) 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}
> x </span>
</div>
</li>
)
};
handleDelete = () => {
this.props.onDelete(this.props.char);
}
}
When you create a function to handle an event, don't forget to add it to your props through the constructor as following:当你创建一个函数来处理一个事件时,不要忘记通过构造函数将它添加到你的 props 中,如下所示:
constructor (props) {
super(props)
this.yourFunction = this.yourFunction.bind(this)
}
By using arrow function, you can solve the this
context.通过使用箭头函数,您可以解决
this
上下文。 Try this:尝试这个:
Your onClick event onClick={this.handleDelete}
您的 onClick 事件
onClick={this.handleDelete}
and your function definition:和你的函数定义:
handleDelete = () => {
//here you can access the this.props
}
Whats happening is when you use this
inside handleDelete
you are not referencing the class.发生的事情是,当您在
handleDelete
使用this
时,您没有引用该类。 You can work around this problem with the followwing approches您可以使用以下方法解决此问题
Using stateless components (best approche in your case)使用无状态组件(最适合您的情况)
Components that dont change the state, dont need to be Class
, you can define them as functions or constants不改变状态的组件,不需要是
Class
,你可以将它们定义为函数或常量
Class Parent extends React.Component {
state = { ... }
onDelete = () => { ... }
render() {
return (
<Child onDelete={this.onDelete} />
)
}
}
function Child(props) {
return (
<button onClick={props.onDelete}>Delete</button>
)
}
Using arrow functions使用箭头函数
Arrow functions dont define a scope, inside an arrow function you are in the class scope.箭头函数不定义作用域,在箭头函数内部,您处于类作用域中。
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>
)
}
}
Using bind使用绑定
If you have a method that uses this
you have to bind the method scope to the class scope, this can be made like folowing.如果你有一个使用
this
的方法,你必须将方法范围绑定到类范围,这可以像下面这样进行。 The bindOnRender
have performance issues due to be called on every render and creating a new function on each call.由于在每次渲染时都被调用并在每次调用时创建一个新函数,因此
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>
)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.