首页 > 解决方案 > 反应:删除后更新状态

问题描述

我正在尝试在删除后更新元素,而不刷新页面。目前,如果删除一条记录,需要刷新一个页面才能看到结果。据我了解,需要更新useState,但我不明白该怎么做。如果我循环它会起作用但速度很慢,但我认为循环响应useEffect不是最好的主意。get

  1. 从数据库中获取所有记录。
const PostsGetUtill = () => {
    const [posts, setPosts] = useState([]);

    const fetchPosts = () => {
        axios.get("api/v1.0/post/get").then(response => {
            console.log(response.data);
            setPosts(response.data);
        }).catch(function (error) {
            if (error.response) {
                console.log(error.response.data);
                console.log(error.response.status);
                console.log(error.response.headers);
            } else if (error.request) {
                console.log(error.request);
            } else {
                console.log('Error', error.message);
            }
            console.log(error.config);
        });
    };

    useEffect(() => {
        fetchPosts();
    }, []);           //  }, [fetchPosts]); <--- working well with loop 

    return (
        <section className="container-post">
            <PostMansonry posts={posts} columns={3} />
        </section>
    );
};

export default PostsGetUtill;
  1. 排序和映射记录
export default function PostMansonry({ posts, columns }) {
    return (
        <section className="masonry" style={{ gridTemplateColumns: `repeat(${columns}, minmax(275px, 1fr))` }}>
            {posts.sort((a, b) => a.zonedDateTime < b.zonedDateTime ? 1 : -1).map((posts, index) =>
                <MasonryPost {...{ posts, index, key: index }} />)
            }
        </section>
    )

}
  1. 将数据放入卡中
export default function MasonryPost({ posts, index }) {
    return (
        <div key={index} className="masonry-post">
            <div className="card">
                <div className="card-body">
                    <h5 className="card-title">{posts.title}</h5>
                    <p className="card-text">{posts.description}</p>
                    <p className="card-text"><small className="text-muted"> {posts.zonedDateTime}</small></p>
                    <div><button type="button" onClick={(e) => PostsDeleteUtill(posts.post_Id)} className="btn btn-danger">Delete</button></div>
                </div>
            </div>
        </div>
    )
}

  1. 删除
const PostsDeleteUtill = async (post_Id) => {
    axios.delete(`api/v1.0/post/delete/${post_Id}`).then(response => {
        console.log(response);
    }).catch((error) => {
        if (error.response) {
            console.log(error.response.data);
            console.log(error.response.status);
            console.log(error.response.headers);
        } else if (error.request) {
            console.log(error.request);
        } else {
            console.log('Error', error.message);
        }
        console.log('error config', error.config);
    });
};

export default PostsDeleteUtill;

标签: reactjsaxios

解决方案


基本上你需要做的是,在你的PostsDeleteUtill函数中,在你的承诺返回中axios.delete,你需要更新你的posts状态,它设置在PostsGetUtill.

为此,您有 2 个选项:

  1. 使用全局状态(React Context、Redux 等)
  2. setPosts将您的手柄一直传递到您的PostsDeleteUtill

我认为选项 1 对于您的特定情况来说更干净一些,但是如果您在项目中的其他任何地方都不需要全局状态,那么最好有一个不太干净的解决方案,而不是只为一个实现整个全局状态结构事物。

选项1伪代码:

您的PostsGetUtill组件将使用全局状态而不是本地状态:

const PostsGetUtill = () => {
    // Remove this:
    // const [posts, setPosts] = useState([]);

    const fetchPosts = () => {
        axios.get("api/v1.0/post/get").then(response => {
            console.log(response.data);
            // Instead of a local "setPosts" you would have a global
            // "setPosts" (in Redux, this would be a dispatch)
            dispatch({type: "PUT_POSTS", action: response.data})
        }).catch(function (error) {
            // No changes here...
        });
    };

    // This runs only the first time you load this component
    useEffect(() => {
        fetchPosts();
    }, []); 

    // Use your global state here as well:
    return (
        <section className="container-post">
            <PostMansonry posts={globalState.posts} columns={3} />
        </section>
    );
};

export default PostsGetUtill;

在您的PostsDeleteUtill功能中:

const PostsDeleteUtill = async (post_Id) => {
    axios.delete(`api/v1.0/post/delete/${post_Id}`).then(response => {
        // Update global state here. Probably filter the data to remove
        // the deleted record
        const updatedPosts = globalState.posts.filter(post => post.id !== response.data.id)
    }).catch((error) => {
      // No changes here
    });
};

export default PostsDeleteUtill;

选项2伪代码:

在您的PostsGetUtill组件中,创建并传递一个handleRemovePost

// Your existing code ...
const handleRemovePost = (postID) => {
    const filteredPosts = posts.filter(post => post.id !=== postID)
    setPosts(filteredPosts)
}

return (
    <section className="container-post">
        <PostMansonry posts={posts} columns={3} handleRemovePost={handleRemovePost} />
    </section>
);

在你的PostMansonry,再次传递你的handleRemovePost

export default function PostMansonry({ posts, columns, handleRemovePost }) {
    return (
        // Your existing code ...
        <MasonryPost {...{ posts, index, key: index, handleRemovePost }} />)
    )
}

再次在你的MasonryPost

export default function MasonryPost({ posts, index, handleRemovePost }) {
    return (
        // Your existing code ...
        <button type="button" onClick={(e) => PostsDeleteUtill(posts.post_Id, handleRemovePost)} className="btn btn-danger">Delete</button>
    )
}

最后:

const PostsDeleteUtill = async (post_Id, handleRemovePost) => {
    axios.delete(`api/v1.0/post/delete/${post_Id}`).then(response => {
        handleRemovePost(response);
    })
};

PS:请注意,我只是添加了一个伪代码作为参考,试图指出代码中需要更新的特定部分。如果您需要有关全局状态的更多信息,可以查看React ContextRedux


推荐阅读