React结合Firebase报错:Cannot read 'setState' of undefined
问题原因与解决方案
你遇到的Uncaught TypeError: Cannot read property 'setState' of undefined错误,核心原因是回调函数里的this指向不对——在then和forEach的普通function回调中,this并没有指向你的Dashboard组件实例,自然找不到setState方法。
另外,你的代码里还有几处小问题需要一起修正,下面一步步来解决:
1. 修复this指向问题
有三种常见方法可以解决这个问题,最推荐第一种(箭头函数),写法最简洁:
方法一:使用箭头函数替换普通function
箭头函数会自动继承外层作用域的this,也就是组件实例。修改你的componentDidMount方法:
componentDidMount() { const w = firebase.auth().currentUser; const rootRef = firebase.database().ref(`restaus/`).orderByKey(); rootRef.once("value") // 这里改成箭头函数 .then((snapshot) => { snapshot.forEach((childSnapshot) => { const key = childSnapshot.key; const childData = childSnapshot.val(); // 现在this指向组件实例,可以正常调用setState了 this.setState({ x: childData.pic }); }); }); this.setState({ email: w.email }); }
方法二:提前保存this的引用
如果习惯用普通function,可以在回调前把组件的this存起来:
componentDidMount() { const w = firebase.auth().currentUser; const rootRef = firebase.database().ref(`restaus/`).orderByKey(); // 保存组件的this引用 const that = this; rootRef.once("value") .then(function (snapshot) { snapshot.forEach(function (childSnapshot) { const key = childSnapshot.key; const childData = childSnapshot.val(); // 使用that代替this that.setState({ x: childData.pic }); }); }); this.setState({ email: w.email }); }
2. 修正render里的错误
你在render里的几个引用需要调整:
<img src={this.x} />应该改成<img src={this.state.x} />,因为x是存在组件的state里的,不是直接挂载在this上的属性。<p className="product-price">{this.props.x}</p>这里的this.props.x看起来是笔误,如果你要显示的是state里的x,应该改成{this.state.x}。
修正后的render部分:
render() { return ( <div> <h4>your email is {this.state.email}</h4> <div className="product"> <div className="product-image"> {/* 改成this.state.x */} <img src={this.state.x} alt="product" /*onClick={this.quickView.bind(this, name)}*/ /> </div> <h4 className="product-name">{this.state.x}</h4> {/* 这里如果是要显示state的x,就改成this.state.x */} <p className="product-price">{this.state.x}</p> <div className="product-action"> <button type="button" >Add To cart</button> </div> </div> </div>) }
额外提醒
注意你的forEach循环会遍历所有的childSnapshot,每次都会调用setState更新x,最终x会被最后一个childData.pic覆盖。如果你的需求是保存所有图片地址,应该把state里的x改成数组,比如:
// constructor里初始化x为数组 this.state = { speed: '', snapshot: undefined, x: [] } // componentDidMount里的forEach部分 snapshot.forEach((childSnapshot) => { const childData = childSnapshot.val(); // 把新的pic添加到数组里 this.setState(prevState => ({ x: [...prevState.x, childData.pic] })); });
这样就能保存所有图片地址,后续在render里可以用map遍历渲染多个图片。
内容的提问来源于stack exchange,提问作者c newbie
相关产品推荐
相关产品推荐

