React发送更新/删除请求无刷新更新视图及表单预填充实现
问题原因
你当前的实现存在两个核心逻辑缺失:
- 发完update/delete请求后,没有同步更新React组件的状态,React无法感知数据变化,自然不会触发重渲染,只能靠手动刷新页面拉取最新数据
- 点击更新按钮唤起表单时,没有将已有帖子数据赋值给表单绑定的状态变量,仅靠placeholder做占位提示,无法实现文本框预填充效果
修复步骤
- 将父组件传入的
post转为组件本地状态管理,接口返回最新数据后直接更新本地状态即可触发页面自动同步更新 - 点击更新按钮打开表单时,把当前帖子的标题、正文、标签内容同步赋值给表单绑定的三个状态变量,textarea通过
value属性绑定对应状态即可实现预填充,不需要使用placeholder - DELETE请求成功后,标记当前帖子为已删除状态,组件直接返回空节点即可从页面移除
- PATCH请求成功后,用接口返回的最新帖子数据替换本地存储的帖子状态,同时关闭编辑表单,页面会自动渲染最新内容
- 修正原代码中
alert提前执行的问题:.then(alert("Post Removed"))会在fetch发起时立刻触发弹窗,需要改为回调函数写法
修复后完整代码
import { useState } from 'react'; export default function PostContainer({post, onPostDelete, onPostUpdate}){ const [isShown, setIsShown] = useState(false); const [isDeleted, setIsDeleted] = useState(false); // 将传入的post转为本地状态管理 const [currentPost, setCurrentPost] = useState(post); const [title, setNewTitle] = useState(""); const [content, setNewContent] = useState(""); const [tags, setNewTags] = useState(""); const userId = currentPost.user_id // 删除成功后直接不渲染当前组件 if (isDeleted) return null; function handleDelete(e){ e.preventDefault(); fetch(`/post/${currentPost.id}`,{ method: "DELETE", headers: { 'Content-Type':'application/json' } }) .then((r) => r.json()) .then(() => { alert("Post Removed") // 标记为已删除,从页面移除 setIsDeleted(true) // 如果父组件维护帖子列表,可调用回调同步父组件状态 onPostDelete && onPostDelete(currentPost.id) }) } // 显示/隐藏更新表单,打开时预填充数据 const handleUpdate = (e) =>{ e.preventDefault(); // 打开表单时预填充现有数据 setNewTitle(currentPost.title); setNewContent(currentPost.content); setNewTags(currentPost.tags.map((tag) => tag.name).join(', ')); setIsShown(current => !current) } // 发送更新请求 function handleSubmit(e){ e.preventDefault(); const patchedPost = { title, content, userId, tags_attributes: tags.split(',').map((el) => { return {name: el.trim()} }) } fetch(`/post/${currentPost.id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify(patchedPost) }) .then((r)=>r.json()) .then((updatedPost) => { // 更新本地帖子状态,触发页面重渲染 setCurrentPost(updatedPost); // 同步父组件列表状态 onPostUpdate && onPostUpdate(updatedPost); // 关闭编辑表单 setIsShown(false); }) } return( <div> <div> {isShown && ( <div> <form className='update-form' onSubmit={handleSubmit}> <label>Title</label><br/> <textarea type='text' value={title} onChange={(e)=>setNewTitle(e.target.value)}></textarea><br/> <label>Content</label><br/> <textarea type='text' value={content} onChange={(e)=>setNewContent(e.target.value)}></textarea><br/> <label>Tags</label><br/> <textarea type='text' value={tags} onChange={(e)=>setNewTags(e.target.value)}></textarea><br/> <button type='submit'>Update</button> <button onClick={(e)=>{e.preventDefault(); setIsShown(false)}}>Cancel</button> </form> </div> )} </div><br/> <div className='postContainer'> <h1>{currentPost.title}</h1> <p className="users-posts-content">{currentPost.content}</p> <p>Tags: {currentPost.tags.map((x)=> x.name).join(', ')}</p> <button onClick={(e)=>handleUpdate(e)}>Update</button> <button onClick={(e)=>handleDelete(e)}>Delete Post</button> </div> </div> ) }
补充说明:如果你的帖子列表是在父组件中统一维护的,直接在父组件修改列表状态后传入子组件即可,不需要在当前组件维护
currentPost和isDeleted状态,整体数据流会更清晰。
内容的提问来源于stack exchange,提问作者Jeffrey
相关产品推荐
相关产品推荐

