Javascript React - TypeError:无法读取未定义的属性“道具”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/50862192/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
React - TypeError: Cannot read property 'props' of undefined
提问by pyan
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;
采纳答案by Vitalik Teremasov
You rewrite the context of the class method when you pass it to props like this because of JS OOP system. So to make it work there are several approaches:
由于 JS OOP 系统,当您像这样将类方法传递给 props 时,您重写了类方法的上下文。因此,要使其发挥作用,有几种方法:
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);
}
}
回答by 5ar
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 thisis, i.e. what it is pointing to.
So when you define:
简而言之(不只是为您,但如果其他人正在阅读此内容),JavaScript 函数定义(如果不是写成箭头函数)重新定义了什么this,即它指向什么。所以当你定义:
handleDelete() {
this.props.onDelete(this.props.char);
}
That function's thisis 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. The thing is that thisexited 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.
该函数this不指向定义它的类的对象实例。如果您来自 C++/C#/Java 背景,这有点违反直觉。事情是this在类进入 JavaScript 之前退出的方式,并且类不仅仅是具有一堆定义的原型的函数的语法糖(参见此处),或者换句话说,默认情况下它不会将 this 绑定到它的函数。
There are a couple typical ways around this:
有几种典型的方法可以解决这个问题:
Bind thisto 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 thison every use of the function(i.e. onClick={this.handleDelete.bind(this)}, but it's not advisablebecause 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 bindis 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)},但它是不可取的,因为它会使你的代码容易出错,如果你忘记给绑定this此外,如果你链接的功能,你可以点。到某处错误的地方。更不用说这bind是一个函数,在 React 中,您将在每次渲染时进行函数调用。但是,如果您遇到必须执行的情况,请this记住这是一件好事改变。
Use arrow functions
使用箭头函数
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 thispointer. 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 thisfrom 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)this从外部作用域(类的作用域)获取 ,但是,因为箭头函数是匿名函数,您可以通过将其分配给name 属性来命名它。
All other solutions are some variations of the two above
所有其他解决方案都是上述两种解决方案的一些变体
Concerning your solution
关于您的解决方案
Both onDeleteand handleDeletesuffer from this thisissue.
双方onDelete并handleDelete由此遭受this的问题。
Also, as @Alyson Maiahas stated above, your Charactercomponent 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>
)
};
}
回答by Sreeram
When you create a function to handle an event, don't forget to add it to your propsthrough the constructor as following:
当你创建一个函数来处理一个事件时,不要忘记通过构造函数将它添加到你的 props 中,如下所示:
constructor (props) {
super(props)
this.yourFunction = this.yourFunction.bind(this)
}
回答by Sagar Jajoriya
By using arrow function, you can solve the thiscontext. Try this:
通过使用箭头函数,您可以解决this上下文。尝试这个:
Your onClick event
onClick={this.handleDelete}
您的 onClick 事件
onClick={this.handleDelete}
and your function definition:
和你的函数定义:
handleDelete = () => {
//here you can access the this.props
}
回答by Alyson Maia
Whats happening is when you use thisinside handleDeleteyou are not referencing the class. You can work around this problem with the followwing approches
发生的事情是当您使用thisinside 时,handleDelete您没有引用该类。您可以使用以下方法解决此问题
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 thisyou have to bind the method scope to the class scope, this can be made like folowing. The bindOnRenderhave performance issues due to be called on every render and creating a new function on each call.
如果你有一个使用的方法,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>
)
}
}

