React中TypeError: Cannot read property 'setState' of undefined问题求助
TypeError: Cannot read property 'setState' of undefined的问题 看起来你遇到的问题核心是函数的this指向不正确,另外代码里还有一个容易忽略的小问题,我来一步步帮你理清:
问题1:checkLogIn函数的this未正确绑定
你虽然在constructor里写了this.checkLogIn = this.checkLogIn.bind(this);,但这里有个潜在的顺序问题:你的pageTemplates是类的实例属性,它的初始化时机是在constructor执行完成之后。这意味着当pageTemplates里的loginPageTemplate被创建时,checkLogIn还没有完成绑定(绑定后的函数还没覆盖原函数),所以按钮的onClick实际上绑定的是未绑定this的原始函数。当你点击按钮时,函数执行时的this是undefined(React在严格模式下运行),自然就会报错找不到setState。
解决方案:用箭头函数定义checkLogIn
箭头函数会自动捕获当前上下文的this,不需要手动绑定,这样能彻底避免this指向问题:
checkLogIn = () => { this.setState({currentPage : this.pageTemplates.mainPageTemplate}); }
用这种方式定义后,你可以删掉constructor里的this.checkLogIn = this.checkLogIn.bind(this);这行代码。
问题2:constructor中提前访问未初始化的pageTemplates
你在constructor里直接用this.pageTemplates.loginPageTemplate初始化state,但pageTemplates作为类实例属性,是在constructor执行完成后才会被添加到实例上的。这意味着你初始化state时,this.pageTemplates还是undefined,会导致初始渲染时没有内容。
解决方案:调整初始化顺序
有两种方式可以解决:
- 把
pageTemplates移到constructor内部定义:
constructor(props) { super(props); // 先定义pageTemplates this.pageTemplates = { loginPageTemplate: ( <div className="loginPage"> <div id='signIn'> <div className='loginPageError'/> <input placeholder="Enter your username" id="loginName" type="text"/> <input placeholder="Enter your password" id="loginPass" type="password"/> <input value="SIGN IN" id="logIn" onClick={this.checkLogIn} type="button"/> </div> </div> ), mainPageTemplate: ( <div id='MainPage'> <div className='mainSidebar'> </div> </div> ) }; // 再初始化state this.state = { currentPage : this.pageTemplates.loginPageTemplate }; }
- 把
pageTemplates定义为类的静态属性:
静态属性属于类本身,不需要等到实例创建就能访问,这样constructor里就能直接用了:
class App extends Component { // 定义静态属性 static pageTemplates = { loginPageTemplate: ( <div className="loginPage"> <div id='signIn'> <div className='loginPageError'/> <input placeholder="Enter your username" id="loginName" type="text"/> <input placeholder="Enter your password" id="loginPass" type="password"/> <input value="SIGN IN" id="logIn" onClick={this.checkLogIn} type="button"/> </div> </div> ), mainPageTemplate: ( <div id='MainPage'> <div className='mainSidebar'> </div> </div> ) }; constructor(props) { super(props); // 用类名访问静态属性 this.state = { currentPage : App.pageTemplates.loginPageTemplate }; } // 其他代码... }
最终修改后的完整代码示例
class App extends Component { constructor(props) { super(props); this.pageTemplates = { loginPageTemplate: ( <div className="loginPage"> <div id='signIn'> <div className='loginPageError'/> <input placeholder="Enter your username" id="loginName" type="text"/> <input placeholder="Enter your password" id="loginPass" type="password"/> <input value="SIGN IN" id="logIn" onClick={this.checkLogIn} type="button"/> </div> </div> ), mainPageTemplate: ( <div id='MainPage'> <div className='mainSidebar'> </div> </div> ) }; this.state = { currentPage : this.pageTemplates.loginPageTemplate }; }; // 用箭头函数定义checkLogIn checkLogIn = () => { this.setState({currentPage : this.pageTemplates.mainPageTemplate}); }; render() { return this.state.currentPage; }; }
这样修改后,不仅能解决setState的报错问题,还能确保初始渲染时有正确的页面内容。
内容的提问来源于stack exchange,提问作者Kitty Captain

