无法从组件访问道具字段

时间:2018-08-21 15:06:07

标签: javascript reactjs react-router

我是ReactJS的新手,但我想创建一个具有登录和注销功能的简单域。我将用户凭据存储在AsyncStorage中。这是我的index.js:

..
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom';
..

class Index extends Component {

    render() {
        return (
            <Router>
                <Switch>
                    <Route path='/' exact component={Home}/>
                    <Route path='/login' component={Login}/>
                    <Route path='/welcome' component={Welcome}/>
                </Switch>
            </Router>
        );
    }

}

ReactDOM.render(<Index />, document.getElementById('root')); registerServiceWorker();

首页页面上,有一个按钮可以移至登录页面:

<Button color="primary" onClick={() => {this.props.history.push("/login")}}>Sign In</Button>

登录组件包含表单,该表单在提交给定方法时调用:

this.props.history.push("/welcome");

最后,在欢迎页面上,我按下了按钮

class Welcome extends Component {

    handleLogout() {
        this.props.history.push("/");
    }

    render() {
        return (
            <div>
                <h1>Hello!</h1>
                <Button onClick={this.handleLogout}>Logout</Button>
            </div>
        );
    }
}

export default withRouter(Welcome);

我想说的是,每个组件(首页登录欢迎)都与Routerr组件一起包装,但是一旦单击欢迎页面上的按钮,发生错误:

  

TypeError:无法读取未定义的属性“历史”

任何帮助将不胜感激:)

4 个答案:

答案 0 :(得分:2)

在javascript中,this的值直到实际调用函数才确定。而且由于onClick是异步发生的,因此handleLogout将在没有上下文的情况下被调用,这意味着this在非严格模式下绑定到窗口对象,或者在严格模式下未定义。您显然处于非严格模式,因此this.props.history.pushwindow.props.history.push相同。 window.props未定义,导致错误。

有几种方法可以解决此问题:

1)在渲染中使用箭头功能。箭头函数与声明时具有相同的值this,因此this将等于您的组件

<Button onClick={(event) => this.handleLogout(event)}/>

2)在构造函数中明确绑定handleLogout函数。这将创建一个新函数,该函数的this的值已锁定。

class Welcome extends Component {
  constructor(props) {
    super(props);
    this.handleLogout = this.handleLogout.bind(this);
  }

  handleLogout() {
    this.props.history.push("/");
  }
  //etc
}

3)如果您使用的是babel-plugin-transform-class-properties插件,请将handleLogout定义为箭头函数:

class Welcome extends Component {
  handleLogout = () => {
    this.props.history.push("/");
  }
  //etc
}

答案 1 :(得分:2)

这与this的定义方式有关。您是在组件的上下文中定义handleLogout,然后将其传递到另一个上下文中并在其中执行。 this在那种情况下会有所不同,因此为何未定义道具。

基本上,如果要将函数传递到其他上下文中(并且您需要从this访问某些内容(例如props或state),则需要将该函数绑定到this的组件版本。可以通过两种常见方式之一来做到这一点

在组件的构造函数中:

constructor(props) {
   super(props)
   this.handleLogout = this.handleLogout.bind(this);
}

或通过使用箭头功能(此“自动绑定”)定义您的方法-但此方法尚未完全批准,因此很可能需要babel polyfill:

handleLogout = () => { // function code }

答案 2 :(得分:1)

这是人们在反应中遇到的一个非常普遍的问题,您没有将适当的范围传递给处理程序函数。因此,在调用handleLogout时,作用域(用'this'表示)不包含道具。您需要先将“ this”绑定到该处理函数,然后再传递给子组件。您可以通过在将按钮提供给Button时使用箭头功能来实现此目的(箭头功能会自动将范围向下传递):

<Button
    onClick={() => this.handleLogout()}
>
    Logout
</Button>

或者您可以将其绑定到构造函数中的处理函数:

class Welcome extends Component {
    constructor(props) {
        super(props);
        this.handleLogout = this.handleLogout.bind(this);
    }

每当您在React中看到指示未定义道具的错误时,“ this”应该是您检查的第一件事。 (双关语意!)

答案 3 :(得分:0)

您应将react-router与Router HOC一起使用,如下所示:

enter image description here 那么您可以从this.props

中读取历史记录