React - TypeError: Cannot read property 'props' of undefined

React - TypeError: Cannot read property 'props' of undefined

我正在尝试创建一个能够删除列表中项目的点击事件,但是当我点击它时,我得到了 "TypeError: Cannot read property 'props' of undefined"。

我尽量坚持使用 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;

由于 JS OOP 系统,当您将 class 方法传递给 props 时,您重写了它的上下文。因此,要使其发挥作用,有几种方法:

1) 这不太好,因为总是绑定 returns 新函数,即使 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) 在我的代码中,我使用箭头函数作为这种情况的 class 属性(我认为这是最常见的解决方案之一)

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);
    }
}

通过使用箭头函数,可以解决this上下文。试试这个:

你的 onClick 事件 onClick={this.handleDelete}

和您的函数定义:

handleDelete = () => {
    //here you can access the this.props
}

当您在 handleDelete 中使用 this 时,您没有引用 class。您可以使用以下方法解决此问题

使用无状态组件(适合您的情况的最佳方法)

不改变状态的组件,不需要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 作用域中。

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>
    )
  }
}

使用绑定

如果您有一个使用 this 的方法,您必须将方法作用域绑定到 class 作用域,这可以像下面那样进行。 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>
    )
  }
}

TLDR:您的代码中的具体问题已在该答案末尾的段落中说明。

这是 Java 脚本 this 的一个 class 逻辑问题,如果您还没有读过,我建议您稍微读一下。

简而言之(不只是为了你,如果其他人正在阅读这篇文章),Java脚本函数定义(如果没有写成 arrow function)重新定义this 是什么,即它指向什么。 所以当你定义它时:

handleDelete() {
     this.props.onDelete(this.props.char);
}

该函数的 this 未指向其中定义的 class 的对象实例。如果您来自 C++/C#/Java背景。问题是 this 在 classes 进入 JavaScript 之前就退出了,而 classes 注意到的不仅仅是具有一堆已定义原型的函数的语法糖(参见 here),或者换句话说,默认情况下它不会将 this 绑定到它的函数。

有几种典型的解决方法:

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,它会使您的代码容易出错。此外,如果您正在链接函数,您可能会指出在某处错误的事情。更不用说 bind 是一个函数,在 React 中你将在每个渲染器上进行函数调用。但是,记住 if 是一件好事您曾经遇到过必须更改 this.

的情况

使用箭头函数

class Character extends Component {
    render() {
        // ...
    };

    handleDelete = () => {
        this.props.onDelete(this.props.char);
    }
}

如上所述,在其他答案中,箭头函数不会重新定义 this 指针。您在这里有效地做的是将箭头函数分配给此 class 的对象实例的属性。换句话说,该函数(作为不重新定义 this 的箭头函数)从外部范围(class 的范围)获取 this,但是,因为箭头函数是匿名的函数,您通过将其分配给 name property.

来命名它

所有其他解决方案都是以上两个的一些变体


关于您的解决方案

onDeletehandleDelete 都遇到了 this 问题。

此外,如 @Alyson Maia has stated above, your Character component can be written as a functional component:

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>
        )
    };
}

当你创建一个函数来处理一个事件时,不要忘记通过构造函数将它添加到你的道具中,如下所示:

constructor (props) {
  super(props)
  this.yourFunction = this.yourFunction.bind(this)
}