反应-TypeError:无法读取未定义的属性'props'

pya*_*yan 9 javascript bind this reactjs react-props

我正在尝试创建一个单击事件,以便能够删除列表中的项目,但是当我单击它时,我收到“ TypeError:无法读取未定义的属性'props'”。

我试图尽可能地坚持使用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;
Run Code Online (Sandbox Code Playgroud)

Vit*_*sov 14

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

1)这不是很好,因为bind alwaus返回新函数,即使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;
Run Code Online (Sandbox Code Playgroud)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*ddy 11

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

constructor (props) {
  super(props)
  this.yourFunction = this.yourFunction.bind(this)
}
Run Code Online (Sandbox Code Playgroud)


5ar*_*5ar 8

TLDR:您的鳕鱼中的特定问题在该答案末尾的段落中说明。

这是JavaScript的经典问题,this如果您还没有读过,建议您阅读一下。

简而言之(不只是为了您,还有其他人正在读的话),JavaScript函数定义(如果未编写为箭头函数)将重新定义内容this,即它所指向的内容。因此,当您定义:

handleDelete() {
     this.props.onDelete(this.props.char);
}
Run Code Online (Sandbox Code Playgroud)

该函数this没有指向其定义的类的对象实例。如果您来自C ++ / C#/ Java背景,这有点违反直觉。问题在于,this在类进入JavaScript之前退出的方式以及类对具有一堆已定义原型的函数的语法糖(请参阅此处)的注意不止于此,或者换句话说,默认情况下它不将其绑定到其函数。

 

有两种典型的解决方法:

 

绑定this到所有函数(在构造函数中)

class Character extends Component {
    constructor(props) {
        super(props)
        this.handleDelete = this.handleDelete.bind(this)
    }
    render() {
        // ...
    };

    handleDelete() {
        this.props.onDelete(this.props.char);
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:除此之外,您可以this在每次使用函数时进行绑定(即onClick={this.handleDelete.bind(this)},但不建议这样做,因为如果您忘记绑定,它会使您的代码易于出错this。此外,如果要链接函数,您可能会指出错误的地方。更不用说这bind是一个函数,在React中,您将在每个渲染器上进行函数调用。但是,如果您不得不在某些情况下this记住这一点,这是一件好事改变

 

使用箭头功能

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

    handleDelete = () => {
        this.props.onDelete(this.props.char);
    }
}
Run Code Online (Sandbox Code Playgroud)

如上所述,在其他答案中,箭头函数不会重新定义this指针。您实际上在这里所做的就是将arrow函数分配给该类的对象实例的一个属性。换句话说,该函数(是未重新定义的箭头函数thisthis从外部范围(该类的范围)中获取,但是,由于箭头函数是匿名函数,因此可以通过将其分配给name属性来对其进行命名

 

所有其他解决方案是上述两种方案的一部分

 


关于您的解决方案

双方onDeletehandleDelete由此遭受this的问题。

另外,正如@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>
        )
    };
}
Run Code Online (Sandbox Code Playgroud)