无法读取为空的属性“上下文”
我一直在学习 Egghead 的“构建你的第一个生产质量 React 应用程序”,一切都很顺利,直到第 17 课,你应该使用
context
来创建你自己的自制路由器组件。据我所知,我做的事情和课程中完全一样,但是当我点击其中一个
Link
组件时,出现此控制台错误:
Link.js:11 Uncaught TypeError: Cannot read property 'context' of null
at handleClick (http://localhost:3000/static/js/bundle.js:33792:12)
at Object.ReactErrorUtils.invokeGuardedCallback (http://localhost:3000/static/js/bundle.js:17162:17)
at executeDispatch (http://localhost:3000/static/js/bundle.js:16945:22)
at Object.executeDispatchesInOrder (http://localhost:3000/static/js/bundle.js:16968:6)
at executeDispatchesAndRelease (http://localhost:3000/static/js/bundle.js:16356:23)
at executeDispatchesAndReleaseTopLevel (http://localhost:3000/static/js/bundle.js:16367:11)
at Array.forEach (native)
at forEachAccumulated (http://localhost:3000/static/js/bundle.js:17265:10)
at Object.processEventQueue (http://localhost:3000/static/js/bundle.js:16570:8)
at runEventQueueInBatch (http://localhost:3000/static/js/bundle.js:24192:19)
链接组件如下所示:
import React, { Component } from 'react';
export class Link extends Component {
static contextTypes = {
route: React.PropTypes.string,
linkHandler: React.PropTypes.func,
}
handleClick(e) {
e.preventDefault();
this.context.linkHandler(this.props.to)
}
render() {
const activeClass = this.context.route === this.props.to ? 'active' : '';
return <a href="#" className={activeClass} onClick={this.handleClick}>{this.props.children}</a>
}
}
Link.propTypes = {
to: React.PropTypes.string.isRequired
}
路由器组件如下所示:
import React, { Component } from 'react';
const getCurrentPath = () => {
const path = document.location.pathname;
return path.substring(path.lastIndexOf('/'));
}
export class Router extends Component {
state = {
route: getCurrentPath()
}
handleLinkClick = (route) => {
this.setState({ route }); // same as { route: route }
history.pushState(null, '', route);
}
static childContextTypes = {
route: React.PropTypes.string,
linkHandler: React.PropTypes.func,
};
getchildContext() {
return {
route: this.state.route,
linkHandler: this.handleLinkClick,
};
}
render() {
return <div>{this.props.children}</div>
}
}
知道是什么原因导致了这个问题吗?
感谢您提供正确的方向!
编辑:
按照我得到的建议(谢谢!),我将
handleClick
绑定在构造函数中(使用箭头函数的结果相同)并验证该函数是否按预期调用,但现在我收到了不同的错误:
Uncaught TypeError: this.context.linkHandler is not a function
at Link.handleClick (http://localhost:3000/static/js/bundle.js:33707:21)
at Object.ReactErrorUtils.invokeGuardedCallback (http://localhost:3000/static/js/bundle.js:17162:17)
at executeDispatch (http://localhost:3000/static/js/bundle.js:16945:22)
at Object.executeDispatchesInOrder (http://localhost:3000/static/js/bundle.js:16968:6)
at executeDispatchesAndRelease (http://localhost:3000/static/js/bundle.js:16356:23)
at executeDispatchesAndReleaseTopLevel (http://localhost:3000/static/js/bundle.js:16367:11)
at Array.forEach (native)
at forEachAccumulated (http://localhost:3000/static/js/bundle.js:17265:10)
at Object.processEventQueue (http://localhost:3000/static/js/bundle.js:16570:8)
at runEventQueueInBatch (http://localhost:3000/static/js/bundle.js:24192:19)
除了需要将函数绑定到
this
之外,如果您绑定了类中不再存在的函数,也可能会发生此错误:
export class Example extends Component {
constructor(props) {
super(props);
this.functionDoesNotExistAnymore = this.functionDoesNotExistAnymore.bind(this);
}
// functionDoesNotExistAnymore() {}
}
这是在 React 中使用 ES6 时常见的问题。您需要将 handleClick 函数绑定到 React 组件的上下文。您可以在组件定义中使用箭头函数来绑定上下文,如下所示
export class Link extends Component {
static contextTypes = {
route: React.PropTypes.string,
linkHandler: React.PropTypes.func,
}
handleClick = (e) => {
e.preventDefault();
this.context.linkHandler(this.props.to)
}
render() {
const activeClass = this.context.route === this.props.to ? 'active' : '';
return <a href="#" className={activeClass} onClick={this.handleClick}>{this.props.children}</a>
}
}
或者您可以在构造函数中绑定它,例如
export class Link extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
...
}
或者您可以在调用时绑定它
onClick={() => this.handleClick()}>
or
onClick={this.handleClick.bind(this)}
为了清楚地回答这个问题,其他人有大量的额外信息可能会让你误入歧途。
引用
You need to bind this to handleClick. You can either do this in a constructor or in onClick (not recommended). onClick={this.handleClick.bind(this)} . Or use an arrow function for handleClick. const handleClick = () = > { }.
– Norm Crandall (来自评论)