React中表单提交后如何无需刷新页面渲染新帖子?
解决React提交帖子后无需刷新页面显示新内容的问题
问题原因
PostList组件仅在挂载阶段通过useEffect(() => {fetchPosts()}, [])调用一次fetchPosts获取帖子数据,后续PostCreate提交新帖子后,PostList没有触发重新获取数据的逻辑,所以新帖子不会自动显示。
解决方案
方案1:状态提升(推荐)
将帖子数据的状态管理提升到父组件App中,让PostCreate提交成功后通知App重新获取数据,再把最新数据传递给PostList。
修改后的App.js代码:
const App = () => { const [posts, setPosts] = useState({}); const fetchPosts = async () => { try { const response = await axios.get(`http://${queries_host}/posts`); setPosts(response.data); } catch (error) { console.log(error); } }; // 组件挂载时获取初始数据 useEffect(() => { fetchPosts(); }, []); return ( <div> <h1>Create Post</h1> <PostCreate onPostCreated={fetchPosts} /> <hr/> <h1>Posts</h1> <PostList posts={posts} /> </div> ); }; export default App;
修改后的PostCreate组件:
const PostCreate = ({ onPostCreated }) => { const [title, setTitle] = useState(''); const onSubmit = async (event) => { event.preventDefault(); try { await axios.post(`http://${posts_host}/posts/create`, { title }); setTitle(''); // 提交成功后通知父组件重新获取帖子 onPostCreated(); } catch (error) { console.log(error); } }; return ( <div> <form onSubmit={onSubmit}> <div className="form-group"> <label>Title</label> <input value={title} onChange={event => setTitle(event.target.value)} className="form-control" /> </div> <button className="btn btn-primary">Submit</button> </form> </div> ) } export default PostCreate;
修改后的PostList组件:
const PostList = ({ posts }) => { const renderedPosts = Object.values(posts).map(post => { return ( <div className="card" style={{width: '30%', marginBottom: '20px'}} key={post.id}> <div className="card-body"> <h3>{post.title}</h3> <CommentList comments={post.comments}></CommentList> <CommentCreate postId={post.id}></CommentCreate> </div> </div> ); }); return ( <div> {renderedPosts} </div> ); } export default PostList;
方案2:使用自定义事件
如果不想提升状态,可以通过自定义事件实现组件间通信:
修改PostCreate组件:
const PostCreate = () => { const [title, setTitle] = useState(''); const onSubmit = async (event) => { event.preventDefault(); try { await axios.post(`http://${posts_host}/posts/create`, { title }); setTitle(''); // 触发自定义事件 window.dispatchEvent(new CustomEvent('postCreated')); } catch (error) { console.log(error); } }; return ( <div> <form onSubmit={onSubmit}> <div className="form-group"> <label>Title</label> <input value={title} onChange={event => setTitle(event.target.value)} className="form-control" /> </div> <button className="btn btn-primary">Submit</button> </form> </div> ) } export default PostCreate;
修改PostList组件:
const PostList = () => { const [posts, setPosts] = useState({}); const fetchPosts = async () => { try { const response = await axios.get(`http://${queries_host}/posts`); setPosts(response.data); } catch (error) { console.log(error); } }; useEffect(() => { fetchPosts(); // 监听自定义事件 const handlePostCreated = () => fetchPosts(); window.addEventListener('postCreated', handlePostCreated); // 组件卸载时移除监听 return () => window.removeEventListener('postCreated', handlePostCreated); }, []); const renderedPosts = Object.values(posts).map(post => { return ( <div className="card" style={{width: '30%', marginBottom: '20px'}} key={post.id}> <div className="card-body"> <h3>{post.title}</h3> <CommentList comments={post.comments}></CommentList> <CommentCreate postId={post.id}></CommentCreate> </div> </div> ); }); return ( <div> {renderedPosts} </div> ); } export default PostList;
内容的提问来源于stack exchange,提问作者watch-this
相关产品推荐
相关产品推荐

