Home > Back-end >  UI not update after delete mutation in apollo client v3.0.0
UI not update after delete mutation in apollo client v3.0.0

Time:01-17

Spesification

Library

  1. @apollo/client": "^3.0.0"
  2. React.JS

GraphQL query : GET_ALL_USERS

query($input: GetAllUserInput) {
        getAllUsers(input: $input) {
            totalPages
            currentPage
            totalItems
            rows {
                email
                username
                created_dtm
                status
                group_id
            }
        }
    }

GraphQL Mutation : DELETE_USER

mutation($username: String!) {
    deleteUser(username: $username) {
        username
    }
}

Problem

1.When I'm click on Delete Button, UI doesn't update but in the backend, item successfully deleted

const TableUserInfo = ({ data }) => {
  const [showModal, setShowModal] = useState(false);

  const [username, setUsername] = useState("");

  const handleShowModal = () => setShowModal(true);
  const handleCloseModal = () => setShowModal(false);

  const userIdtoDelete = data.getAllUsers.rows.map((row) => row.username);
  const userIdToString = userIdtoDelete.toString();

  const [deleteUser, { error, loading, refetch }] = useMutation(DELETE_USER, {
    variables: { username: userIdToString },
    update(cache, { data }) {
      const { getAllUsers } = cache.readQuery({ query: GET_ALL_USERS });

      cache.writeQuery({
        query: GET_ALL_USERS,
        data: {
          getAllUsers: getAllUsers.filter(
            (user) => user.username !== userIdToString
          ),
        },
      });
    },
    onCompleted: () => {
      refetch();
    },
    one rror: (error) => {
      console.log(JSON.stringify(error, null, 2));
    },
  });
...
      <Button
                key="Hapus"
                variant="outline-danger"
                onClick={deleteUser}
                disabled={loading}
                className="d-block btn-block btn-sm mb-2 w-100"
              >
                Hapus
              </Button>

Additional Info : Data comes from parent. here is the parent code :

const PengaturanPengguna = () => {
  // pagination
  const [currentPage, setCurrentPage] = useState(1);
  const sizeFetchDataPerPage = 10;

  const { data, refetch, loading, error } = useQuery(GET_ALL_USERS, {
    variables: {
      input: {
        size: sizeFetchDataPerPage,
        page: currentPage,
      },
    },
  });

  const totalPages = data?.getAllUsers.totalPages;

  useEffect(() => {
    if (data) {
      setCurrentPage(data?.getAllUsers.currentPage);
    }
  }, [data])

  if (loading) return <p>Loading...</p>;
  if (error)
    return (
      <p>
        Error... {error.message} {console.log(JSON.stringify(error, null, 2))}{" "}
      </p>
    );

  // refetch data
  const handleRefreshClick = () => {
    refetch();
  };

  return (
    <Container>
      <CardInfo data={data} />
      <Card>
        <Card.Title>
          <span className="base-md text-regular mt-2 std-txt-primary-200">
            Data Pengguna Dashboard
          </span>
        </Card.Title>
        <Card.Body>
          <div className="d-flex justify-content-between">
            <Form inline>
              <Search />
              <Button variant='secondary' onClick={handleRefreshClick} disabled={loading}>{loading ? 'Loading...' : 'Muat Ulang'}</Button>
            </Form>
            <div>
              <Button variant="success">Daftar Akun</Button>
            </div>
          </div>
          <TableUserInfo data={data} /> //heres the table
          <div className="d-flex justify-content-between">
            <div className="align-self-center">
              <span>Keterangan : </span>
              <StyledDiv>
                <Legend color="#40B4BA" />
                <StyledSpan>Aktif</StyledSpan>
              </StyledDiv>
              <StyledDiv>
                <Legend color="#78909C" />
                <StyledSpan>Tidak Aktif</StyledSpan>
              </StyledDiv>
            </div>
            <PageNavigator
              totalPages={totalPages}
              currentPage={currentPage}
              setCurrentPage={setCurrentPage}
            />
          </div>
        </Card.Body>
      </Card>
    </Container>
  );
};
  1. I got this error information enter image description here

What I've Tried I'm using refetchQueries, update method with cache.readQuery() and cache.writeQuery but UI still doesn't update.

Question How to make delete mutation deleted data in the backend and update the UI based on my query and mutation spesification ?

CodePudding user response:

maybe you are missing the rows here:

 getAllUsers: {
   ...getAllUsers,
   totalItems: getAllUsers.totalItems - 1,
   rows: getAllUsers.rows.filter((user) => user.username !== userIdToString)
 },

CodePudding user response:

When you read/write a query from the cache you must pass the same variables as the orinigal query, and to do that you can use the variables returned from the original query:

Parent component

const { data, refetch, loading, error, variables } = useQuery(GET_ALL_USERS, {
    variables: {
      input: {
        size: sizeFetchDataPerPage,
        page: currentPage,
      },
    },
  });

...

<TableUserInfo data={data} variables={variables} /> //heres the table

...

Child component

const TableUserInfo = ({ data, variables }) => {

...

const { getAllUsers } = cache.readQuery({ query: GET_ALL_USERS, variables });

cache.writeQuery({
  query: GET_ALL_USERS,
  variables,
  data: {
    getAllUsers: getAllUsers.filter(
      (user) => user.username !== userIdToString
    ),
  },
});

...

Also I think this part of the code is wrong:

const userIdtoDelete = data.getAllUsers.rows.map((row) => row.username);
const userIdToString = userIdtoDelete.toString();

...

data: {
          getAllUsers: getAllUsers.filter(
            (user) => user.username !== userIdToString
          ),
},

First you access row property of getAllUsers, you return an array of username then you use .toString() in this array, but when you update the cache you use .filter directly on getAllUsers and you compare the username property with the stringified array of username (userIdToString), so I think you should verify this part for possible mistakes

  • Related