我正在学习,同时创建一个测试应用程序,可以让你创建一个表单的帖子。我已经卡在删除功能上已经五天了。
我能够正确地映射帖子,将post_body打印到每一张卡上,但是当尝试删除时,它总是删除数据库中的最后一项。
我的猜测是,这与道具有关,我花了几天时间尝试不同的方法,通过一个功能组件传递道具,但没有运气。
如屏幕截图所示,在返回时,我为每一张卡片打印了post_id,这样您就可以看到为每一张卡指定了正确的ID。但是,一旦您进入popover组件,post_ID似乎总是使用最底层post的值。
任何方向都是感激的。
(注意:我确信这段代码相当草率,我可能不应该在这么大的代码块上映射。一旦我弄清楚这些道具应该如何工作,我可能会尝试重构)
const ListPosts = (props) => {
const [posts, setPosts] = useState([]);
// Delete Post
const deletePost = async id => {
try {
const deletePost = await fetch(`http://localhost:3000/posts/${id}`, {
method: "DELETE"
});
setPosts(posts.filter(post => post.post_id !== id));
console.log(deletePost);
} catch (err) {
console.error(err.message);
}
}
// Options Popover
const [show, setShow] = useState(false);
const [target, setTarget] = useState(null);
const ref = useRef(null);
const handleClick = (event) => {
setShow(!show);
setTarget(event.target);
}
// Get Posts Function
const getPosts = async() => {
try {
const response = await fetch("http://localhost:3000/posts")
const jsonData = await response.json()
setPosts(jsonData);
} catch (err) {
console.error(err.message)
}
};
useEffect(() => {
getPosts();
}, []);
console.log(posts);
return (
<Fragment>
{/* Map Post Text */}
{posts.map(post => (
<Card className="post-card" style={{ marginTop: "15px" }} key={post.post_id}>
<Card.Body>
<div className="post-container">
<div className="post-header row">
<div className="user-photo-icon col-1"></div>
<div className="user-names col-9"></div>
<div className="options-menu col-2 ">
<div ref={ref}>
<Button className="options-btn-popover" onClick={handleClick}>
<FontAwesomeIcon icon={ faEllipsisH } color="#848484" size="1x" className="options-icon" />
</Button>
{/* Placed to show the point at which the ID's are still correct */}
{post.post_id}
<Overlay
show={show}
target={target}
placement="left"
container={ref.current}
>
<Popover className="shadow-sm" id="popover-contained" >
{/* Placed to show that now all id's show the post_id of the last post */}
{post.post_id}
<Popover.Content>
<div className="mb-2">
<Button className="options-btn-popover">
<FontAwesomeIcon icon={ faPencilAlt } size="1x" className="post-options-icon"/>
Edit Post
</Button>
</div>
<div>
<Button className="options-btn-popover" onClick={() => deletePost(post.post_id)}>
<FontAwesomeIcon icon={ faTrashAlt } color="" size="1x" className="post-options-icon" />
Delete Post
</Button>
</div>
</Popover.Content>
</Popover>
</Overlay>
</div>
</div>
</div>
<div className="post-text">{post.post_body}</div>
<div className="post-media"></div>
<div className="post-actions"></div>
<div className="post-comments">
<div className="post-subcomments"></div>
</div>
</div>
</Card.Body>
</Card>
))}
</Fragment>
)
};这是一张截图:
发布于 2021-06-04 20:51:13
问题
我怀疑这是因为您只有一个show状态,当切换时打开,所有的,弹出框。所有的弹出式都是打开的,但它们都是相对于target元素的位置,它们都是重叠的,最后一个是在顶部。
解决方案
我建议将当前的post id存储在“显示”状态中,并有条件地检查/匹配以打开特定的弹出。
null初始状态开始:
setShow = useState(null);show状态设置为当前单击的post id。
handleClick = (postId) => (事件) => { setShow(postId);setTarget(event.target);}post.post_id。
show状态中的内容匹配,则计算true,否则为false。
. show状态。函数状态更新以正确地从以前的状态(而不是从回调触发的呈现周期中的状态)进行更新。
deletePost =异步=> {http://localhost:3000/posts/${id},{方法:“删除”};setPosts(post => posts.filter(post => post.post_id !== id));// <-函数更新console.log( deletePost );} catch (err) { console.error(err.message);}最后{ setShow( null );// <- reset to null}发布于 2021-06-04 20:50:20
你能试着用竞逐来完成这个任务吗?
下面是我做的一个小改动的代码。当我们声明deletePost时,您会注意到它将id作为param,然后调用另一个函数。然后,当您调用这个delete函数时,您不再需要在=>之前使用() deletePost。
TLDR: currying允许您在执行时间之前传入值。
const ListPosts = (props) => {
const [posts, setPosts] = useState([]);
// Delete Post
const deletePost = id => async => {
try {
const deletePost = await fetch(`http://localhost:3000/posts/${id}`, {
method: "DELETE"
});
setPosts(posts.filter(post => post.post_id !== id));
console.log(deletePost);
} catch (err) {
console.error(err.message);
}
}
// Options Popover
const [show, setShow] = useState(false);
const [target, setTarget] = useState(null);
const ref = useRef(null);
const handleClick = (event) => {
setShow(!show);
setTarget(event.target);
}
// Get Posts Function
const getPosts = async() => {
try {
const response = await fetch("http://localhost:3000/posts")
const jsonData = await response.json()
setPosts(jsonData);
} catch (err) {
console.error(err.message)
}
};
useEffect(() => {
getPosts();
}, []);
console.log(posts);
return (
<Fragment>
{/* Map Post Text */}
{posts.map(post => (
<Card className="post-card" style={{ marginTop: "15px" }} key={post.post_id}>
<Card.Body>
<div className="post-container">
<div className="post-header row">
<div className="user-photo-icon col-1"></div>
<div className="user-names col-9"></div>
<div className="options-menu col-2 ">
<div ref={ref}>
<Button className="options-btn-popover" onClick={handleClick}>
<FontAwesomeIcon icon={ faEllipsisH } color="#848484" size="1x" className="options-icon" />
</Button>
{/* Placed to show the point at which the ID's are still correct */}
{post.post_id}
<Overlay
show={show}
target={target}
placement="left"
container={ref.current}
>
<Popover className="shadow-sm" id="popover-contained" >
{/* Placed to show that now all id's show the post_id of the last post */}
{post.post_id}
<Popover.Content>
<div className="mb-2">
<Button className="options-btn-popover">
<FontAwesomeIcon icon={ faPencilAlt } size="1x" className="post-options-icon"/>
Edit Post
</Button>
</div>
<div>
<Button className="options-btn-popover" onClick={deletePost(post.post_id)}>
<FontAwesomeIcon icon={ faTrashAlt } color="" size="1x" className="post-options-icon" />
Delete Post
</Button>
</div>
</Popover.Content>
</Popover>
</Overlay>
</div>
</div>
</div>
<div className="post-text">{post.post_body}</div>
<div className="post-media"></div>
<div className="post-actions"></div>
<div className="post-comments">
<div className="post-subcomments"></div>
</div>
</div>
</Card.Body>
</Card>
))}
</Fragment>
)
};发布于 2021-06-04 20:52:18
我认为问题在于您要在循环内部创建Overlay/Popover组件,尝试将其移出循环。然后,您可以使用const [selectedPost, selectPost] = useState()来跟踪应该在覆盖层中呈现的数据。按钮被点击了。还调整onClick={handleClick}以调用selectPost(post)。
https://stackoverflow.com/questions/67843424
复制相似问题