React经axios向Express发POST存库后页面不自动重渲染,需手动刷新
点击发布后内容不自动更新的原因与解决方法
核心问题原因
ViewerList中的useEffect设置了空依赖数组,仅会在组件首次挂载时发起一次GET请求拉取数据,后续没有组件重挂载的触发条件时,永远不会再次拉取数据库的最新内容Poster与ViewerList是相互独立的组件,Poster完成POST请求写入数据库后,没有任何跨组件通信机制通知ViewerList重新获取数据,因此只有手动刷新页面触发整页重加载,才会执行ViewerList的初始拉取逻辑,展示新发布的内容。
具体实现方法
推荐方案:状态提升(无额外依赖,适配当前项目规模)
把数据列表的状态、拉取数据的逻辑上移到两个组件的共同父组件中统一管理,实现跨组件联动:
- 父组件持有列表状态,封装可复用的列表拉取方法
- 将拉取方法作为属性传给Poster,在POST请求成功的回调中调用该方法,触发列表重新拉取
- 将父组件维护的列表数据作为属性传给ViewerList完成渲染
对应的代码调整:
- 共同父组件示例:
import { useState, useEffect } from 'react'; import Poster from './Poster'; import ViewerList from './ViewerList'; import axios from 'axios'; const url = "http://localhost:3001/"; function Home() { // 上移的列表状态 const [myData, setMyData] = useState([]); // 封装通用拉取方法 const fetchList = () => { axios.get(url) .then(res => setMyData(res.data)) .catch(err => console.log(err)); } // 首次挂载时拉取初始数据 useEffect(() => { fetchList(); }, []) return ( <div> {/* 将拉取方法传给Poster,支持提交成功后触发更新 */} <Poster onPostSuccess={fetchList} /> {/* 将列表数据传给ViewerList渲染 */} <ViewerList listData={myData} /> </div> ) }
- 调整Poster组件的逻辑:
原代码中同时使用受控
value={topic}和ref读取文本域值属于重复逻辑,直接使用state值提交即可,无需额外引入ref
import React, { useState } from 'react'; import axios from "axios"; import qs from "qs"; function Poster({ onPostSuccess }) { const [topic, topicSetter] = useState(""); const url = "http://localhost:3001/"; function update(ev) { topicSetter(ev.target.value) } function Submit(event){ event.preventDefault(); // 直接使用受控state值提交 const toPostTopic = {"idea": topic}; axios.post(url, qs.stringify(toPostTopic)) .then((res)=>{ console.log(res.data); // POST成功后触发父组件重新拉取最新列表 onPostSuccess(); }) // 清空输入框 topicSetter(""); } return( <form onSubmit={(e)=>Submit(e)}> <textarea placeholder="Tell us your perfect idea..." onChange={update} type="text" cols="50" rows="2" maxLength="100" className="table table-boarded poster-form" name="ideaPosted" value={topic} /> <button type="submit" className="btn btn-primary btn-lg btn-block poster-form-btn">Post</button> </form> ); } export default Poster;
- 调整ViewerList组件,移除内部拉取逻辑,直接接收父组件传入的列表数据渲染:
import React from 'react'; import Viewer from "./Viewer" function ViewerList({ listData }) { return ( <div> {listData.map((ide)=> <Viewer key={ide.key} idea={ide.idea}/>)} </div> ) } export default ViewerList;
其他可选方案
如果项目后续组件层级较多,也可以通过Context、Redux等全局状态管理工具共享列表状态,在POST请求成功后直接更新全局状态中的列表数据,省去重复请求的开销,不过对于当前规模的应用,状态提升的实现成本更低。
内容的提问来源于stack exchange,提问作者Waleed Elian
相关产品推荐
相关产品推荐

