React学习项目报错:Uncaught ReferenceError及列表重渲染问题求助
你的React项目问题解决方案
我来帮你一步步搞定这两个问题:
1. 先解决"Uncaught ReferenceError: val is not defined"报错
这个错误其实是两个小问题导致的:
- 你在
setState里写了{val},这是ES6的对象简写语法,只有当你有一个同名变量时才能这么用,但这里你根本没声明过val变量,JS自然找不到它,直接报错。 - 更重要的是,你直接修改了React的state:
this.state.val.push(msg)这种写法是React的大忌,因为React的state设计成不可变的,直接改原state会让React检测不到状态变化,后续渲染肯定出问题。
正确的写法是创建一个新数组,把新消息加进去,再通过setState更新:
handleSend(msg) { // 用扩展运算符复制原数组,再加入新消息,不碰原state const updatedMessages = [...this.state.val, msg]; this.setState({ val: updatedMessages }); }
如果你习惯用concat也可以,效果一样:
handleSend(msg) { const updatedMessages = this.state.val.concat(msg); this.setState({ val: updatedMessages }); }
2. 实现新增帖子后自动刷新
你之前改成this.setState({val: []})后要刷新才显示,是因为你把本地state清空了,但新数据根本没同步进来。要自动渲染,分两种情况处理:
情况1:AddMsg组件已经处理了POST请求,成功后传msg给你
如果AddMsg组件已经完成了后端POST请求,确认成功后才调用onSend(msg),那用上面的handleSend写法就够了——React检测到state里的数组变了,会自动重新渲染<ul>列表,不用刷新页面。
情况2:需要从后端拉取最新的完整消息列表
如果你的场景里可能有其他用户也在加消息,或者后端会对消息做处理(比如加ID),那最好在POST成功后重新拉取一次最新数据:
首先把componentDidMount里的fetch逻辑抽成单独方法,方便复用:
fetchMessages = () => { fetch('http://localhost:3003/api/msgs/') .then(res => res.json()) .then(data => this.setState({ val: data })) .catch(console.error); } componentDidMount() { this.fetchMessages(); }
然后修改handleSend,先发送POST请求,成功后调用上面的方法拉取最新数据:
handleSend(msg) { // 先给后端发POST请求,把新消息传过去 fetch('http://localhost:3003/api/msgs/', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ msgdata: msg }), // 这里根据你后端接口的参数调整 }) .then(res => res.json()) .then(() => { // 请求成功后,重新拉取最新消息列表,自动更新UI this.fetchMessages(); }) .catch(console.error); }
这样操作后,新增消息成功后页面会自动刷新列表,不用手动刷新。
额外给你两个优化小建议
- 别用数组index当
key:你现在用index作为<li>的key,当列表有增删时,React可能会渲染出错,建议用后端返回的msg._id当key,比如<li dir="rtl" key={msg._id} className='myli'>。 - 提前绑定
this:你现在用bind(this)的方式每次render都会创建新函数,有点浪费性能,不如在构造函数里绑定:
constructor(props, context) { super(props, context); this.state = { val: [] }; // 提前绑定this,后续直接用 this.handleSend = this.handleSend.bind(this); this.deleteMsg = this.deleteMsg.bind(this); }
然后render里直接写<AddMsg onSend={this.handleSend}/>就行啦。
内容的提问来源于stack exchange,提问作者Nauruto
相关产品推荐
相关产品推荐

