简体   繁体   English

React - TypeError:无法读取未定义的属性“道具”

[英]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:有几种典型的方法可以解决这个问题:

Bind 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情况的情况

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 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所有其他解决方案都是上述两种解决方案的一些变体


Concerning your solution关于您的解决方案

Both onDelete and handleDelete suffer from this this issue. onDeletehandleDeleteonDelete 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.

相关问题 React TypeError:在传递道具时无法读取未定义的属性“map” - React TypeError: Cannot read property 'map' of undefined on passing props React教程:TypeError:无法读取未定义的属性“ props” - React Tutorial: TypeError: Cannot read property 'props' of undefined TypeError:无法读取undefined的属性'firstName' - 在react中使用'props' - TypeError: Cannot read property 'firstName' of undefined - using 'props' in react React/Redux - TypeError:无法读取未定义的属性“道具” - React/Redux - TypeError: Cannot read property 'props' of undefined TypeError:无法读取 React function 中未定义的属性“道具” - TypeError: Cannot read property 'props' of undefined In a React function 反应功能组件类型错误:无法读取未定义的属性“道具” - React functional component TypeError: Cannot read property 'props' of undefined React Redux - TypeError:无法读取未定义的属性“道具” - React Redux - TypeError: Cannot read property 'props' of undefined React Redux - Uncaught(in promise)TypeError:无法读取未定义的属性&#39;props&#39; - React Redux - Uncaught (in promise) TypeError: Cannot read property 'props' of undefined 未捕获的TypeError:无法读取react-redux中未定义的属性&#39;props&#39; - Uncaught TypeError: Cannot read property 'props' of undefined in react-redux (TypeError):无法读取未定义的属性“ props” - (TypeError): Cannot read property 'props' of undefined
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM