Search code examples
javascriptreactjsreact-hooksuse-effectmern

React UseEffect not updating when information is deleted from array


I'm looking to get some help as I've been stuck on this for a while. I have a MERN stack application interacting with the Github API. Users are able to search for Github users and save them to their profile on the app and once they do that they will also start following the user on Github. In the same fashion users are able to delete the users from their profile in the app and that will unfollow the same user on Github. The problem is that when I click on the delete user button, it does not update on the browser unless I refresh the page then I see that the user is deleted from the array of saved users. In the Profile.jsx component I am rendering the list of saved users and fetching the information from the database. In the SavedGithubUsersCard.jsx component I am mapping through the saved users data to render the user's information such as name. In DeleteButton.jsx I am deleting the specific saved user when I click on the button. My question is what am I doing wrong? is the prop change not being fired or is there another issue with UseEffect?

Here is the code:

    import React, { useEffect, useContext } from 'react';
import swal from 'sweetalert';
import { AppContext } from '../context/AppContext';
import SavedGithubUsersCard from './SavedGithubUsersCard';
import axios from 'axios';

Profile.jsx
const Profile = () => {
  const {
    githubUserData, setGithubUserData
  } = useContext(AppContext);

  useEffect(() => {
    axios.get('/api/githubdata').then((res) => {
        setGithubUserData(res.data);
      })
      .catch((err) => {
        if (err) {
          swal('Error', 'Something went wrong.', 'error');
        }
      });
  }, [setGithubUserData]);

  return (
    <div className="profile-saved-users">
    <div className="githubUserData-cards">
    <h1 className="saved-users-header">Saved users</h1>
      {!githubUserData || githubUserData.length === 0 ? (
        <p className="no-saved-users-text">No saved users yet :(</p>
      ) : (
       <SavedGithubUsersCard githubUserData={githubUserData}/>
      )}
    </div>
    </div>
  );
};

export default Profile;



 import React from 'react';
import { Card, Button } from 'react-bootstrap';
import { Link } from 'react-router-dom';
import DeleteButton from './DeleteButton';

SavedGithubUsersCard.jsx

const SavedGithubUsersCard = ({githubUserData}) => {
    
    return (
        <>
           {githubUserData?.map(githubUserData => (
            <Card key={githubUserData._id} id="saved-users-card">
            <Card.Img
              variant="top"
              src={githubUserData.avatar_url}
              id="saved-users-card-image"
            />
            <Card.Body id="saved-users-card-information">
              <Card.Title
                id="saved-users-name"
                style={{ textAlign: 'center' }}
              >
                {githubUserData.name}
              </Card.Title>
              <Card.Subtitle
                id="saved-users-username"
                className="mb-2 text-muted"
                style={{ textAlign: 'center' }}
              >
                {githubUserData.login}
              </Card.Subtitle>
              <Card.Text id="saved-users-profile-url">
                Profile URL: {githubUserData.html_url}
              </Card.Text>
              <Link
                to={{ pathname: "githubUserData.html_url" }}
                target="_blank"
              >
                <Button
                  id="saved-users-profile-button"
                  variant="outline-primary"
                >
                  View profile
                </Button>
              </Link>
                <DeleteButton githubUserDataId={githubUserData._id} githubUserDataLogin= {githubUserData.login} />           
              </Card.Body>
          </Card>
             ))}
        </>
      );
    };

export default SavedGithubUsersCard

DeleteButton.jsx

    import React from 'react';
import { Button } from 'react-bootstrap';
import axios from 'axios';
import swal from 'sweetalert';

const DeleteButton = ({ githubUserDataLogin, githubUserDataId }) => {

  const handleRemove = async () => {
    try {
      fetch(`https://api.github.com/user/following/${githubUserDataLogin}`, {
        method: 'DELETE',
        headers: {
          Authorization: `token ${process.env.GITHUB_TOKEN}`
        }
      });
      await axios({
        method: 'DELETE',
        url: `/api/githubdata/${githubUserDataId}`,
        withCredentials: true
      });
      swal(
        'Removed from profile!',
        `You are no longer following ${githubUserDataLogin} on Github`,
        'success'
      );
    } catch (err) {
      swal('Error', 'Something went wrong.', 'error');
    }
  };

  return (
    <Button
      variant="outline-danger"
      style={{ marginLeft: 20 }}
      onClick={handleRemove}
      id="saved-users-delete-button"
    >
      Remove User
    </Button>
  );
};

export default DeleteButton;

AppContext.jsx

import React, { createContext, useState, useEffect } from 'react';
import axios from 'axios';

const AppContext = createContext();

    const AppContextProvider = ({ children }) => {
      const [currentUser, setCurrentUser] = useState(null);
      const [loading, setLoading] = useState(false);
      const [githubUserData, setGithubUserData] = useState([]);
      const user = sessionStorage.getItem('user');
    
      useEffect(() => {
        // incase user refreshes and context is cleared.
        if (user && !currentUser) {
          axios
            .get(`/api/users/me`, {
              withCredentials: true
            })
            .then(({ data }) => {
              setCurrentUser(data);
            })
            .catch((error) => console.error(error));
        }
      }, [currentUser, user]);
    
      return (
        <AppContext.Provider
          value={{ currentUser, setCurrentUser, loading, setLoading, githubUserData, setGithubUserData}}
        >
          {children}
        </AppContext.Provider>
      );
    };
    
    export { AppContext, AppContextProvider };

Thank you!


Solution

  • From what I see of your code when you delete a user you successfully delete them in the back end but don't also update the local state.

    Option 1 - Refetch the users list and update local state

    const DeleteButton = ({ githubUserDataLogin, githubUserDataId }) => {
      const { setGithubUserData } = useContext(AppContext);
    
      const handleRemove = async () => {
        try {
          fetch(....);
    
          await axios(....);
    
          swal(....);
    
          const usersDataRes = await axios.get('/api/githubdata');
          setGithubUserData(usersDataRes.data);
        } catch (err) {
          swal('Error', 'Something went wrong.', 'error');
        }
      };
    
      return (
        ...
      );
    };
    

    Option 2 - Attempt to manually synchronize the local state

    const DeleteButton = ({ githubUserDataLogin, githubUserDataId }) => {
      const { setGithubUserData } = useContext(AppContext);
    
      const handleRemove = async () => {
        try {
          fetch(....);
    
          await axios(....);
    
          swal(....);
    
          setGithubUserData(users => 
            users.filter(user => user._id !== githubUserDataId)
          );
        } catch (err) {
          swal('Error', 'Something went wrong.', 'error');
        }
      };
    
      return (
        ...
      );
    };