Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why do I have to refresh the page when I delete a post? MERN stack

I am a beginner in the MERN stack and I am interested in why I have to refresh the page after deleting the document (post)?

This is my Action.js

export const deletePost = id => async (dispatch, getState) => {
  try {
    dispatch({ type: DELETE_POST_BEGIN });

    const {
      userLogin: { userInfo },
    } = getState();

    const config = {
      headers: {
        Authorization: `Bearer ${userInfo.token}`,
      },
    };

    const { data } = await axios.delete(`/api/v1/post/${id}`, config);

    dispatch({ type: DELETE_POST_SUCCESS, payload: data });
  } catch (error) {
    dispatch({
      type: DELETE_POST_FAIL,
      payload: { msg: error.response.data.msg },
    });
  }
};

This is my Reducer.js

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

export const deletePostReducer = (state = {}, action) => {
  switch (action.type) {
    case DELETE_POST_BEGIN:
      return { loading: true };
    case DELETE_POST_SUCCESS:
      return { loading: false };
    case DELETE_POST_FAIL:
      return { loading: false, error: action.payload.msg };
    default:
      return state;
  }
};

And this is my Home page where i list all posts:

import { useEffect } from 'react';
import { Col, Container, Row } from 'react-bootstrap';
import { useDispatch, useSelector } from 'react-redux';
import { getPosts } from '../actions/postActions';
import Loader from '../components/Loader';
import Message from '../components/Message';
import Post from '../components/Post';

const HomePage = () => {
  const dispatch = useDispatch();

  const allPosts = useSelector(state => state.getPosts);
  const { loading, error, posts } = allPosts;

  const deletePost = useSelector(state => state.deletePost);
  const { loading: loadingDelete } = deletePost;

  useEffect(() => {
    dispatch(getPosts());
  }, [dispatch]);

  return (
    <Container>
      {loading || loadingDelete ? (
        <Loader />
      ) : error ? (
        <Message variant='danger'>{error}</Message>
      ) : (
        <>
          <Row>
            {posts.map(post => (
              <Col lg={4} key={post._id} className='mb-3'>
                <Post post={post} />
              </Col>
            ))}
          </Row>
        </>
      )}
    </Container>
  );
};

export default HomePage;

And this is my single Post component:

const Post = ({ post }) => {
  const dispatch = useDispatch();

  const allPosts = useSelector(state => state.getPosts);
  const { loading, error, posts } = allPosts;

  const userLogin = useSelector(state => state.userLogin);
  const { userInfo } = userLogin;

  const handleDelete = id => {
    dispatch(deletePost(id));
  };

  return (
    <>
      <div>{post.author.username}</div>
      <Card>
        <Card.Img variant='top' />
        <Card.Body>
          <Card.Title>{post.title}</Card.Title>
          <Card.Text>{post.content}</Card.Text>
          <Button variant='primary'>Read more</Button>
          {userInfo?.user._id == post.author._id && (
            <Button variant='danger' onClick={() => handleDelete(post._id)}>
              Delete
            </Button>
          )}
        </Card.Body>
      </Card>
    </>
  );
};

And my controller:

const deletePost = async (req, res) => {
  const postId = req.params.id;
  const post = await Post.findOne({ _id: postId });

  if (!post.author.equals(req.user.userId)) {
    throw new BadRequestError('You have no permission to do that');
  }

  await Post.deleteOne(post);

  res.status(StatusCodes.NO_CONTENT).json({
    post,
  });
};

I wish someone could help me solve this problem, it is certainly something simple but I am a beginner and I am trying to understand.

>Solution :

I believe the issue is that you are not fetching the posts after delete is successful.

Try this inside the HomePage component:

...
const [isDeleting, setIsDeleting] = useState(false);
const { loading: loadingDelete, error: deleteError } = deletePost;

useEffect(() => {
    dispatch(getPosts());
}, [dispatch]);

useEffect(() => {
    if (!deleteError && isDeleting && !loadingDelete) {
        dispatch(getPosts());
    }
    setIsDeleting(loadingDelete);        
}, [dispatch, deleteError, isDeleting, loadingDelete]);
...

Another method is to use "filtering", but you have to update your reducer as such:

export const deletePostReducer = (state = {}, action) => {
  switch (action.type) {
    case DELETE_POST_BEGIN:
      return { loading: true };
    case DELETE_POST_SUCCESS:
      return { loading: false, data: action.payload.data }; // <-- this was changed
    case DELETE_POST_FAIL:
      return { loading: false, error: action.payload.msg };
    default:
      return state;
  }
};

Now in your HomePage component, you will do something like this when rendering:

...
const { loading: loadingDelete, data: deletedPost } = deletePost;
...
return (
   ...
   <Row>
     {posts.filter(post => post._id !== deletedPost?._id).map(post => (
        <Col lg={4} key={post._id} className='mb-3'>
           <Post post={post} />
        </Col>
     ))}
   </Row>
)
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading