Refresh a component after a CRUD operation

Hello! I keep my question generic, then I’ll go into more details if needed.

I have a table with entries and some action buttons (among which there is one to delete an entry), then a button to add a new entry. Now, when I use the form to save the data, the entry gets inserted on the db side, however on the frontend I have to refresh the page to see the change. Same goes if I delete an entry. How is this handled in Redwood?

I’ve also not quite worked this out, I have something similar, although my items get created on a separate page.

I have got it working that when I update an item from the list the table of items updates, and this depends on making sure that my mutation retrieves the fields that have changed (in this case status, and endActualDateTime.

  mutation CompleteHireSessionMutation(
    $id: String!
    $input: UpdateHireSessionInput!
  ) {
    completeHireSession(id: $id, input: $input) {

In this example here, when I click the button an item to update it’s status, the status field updates automatically.

I’ve not worked out how to get it to update the table automatically when an item is deleted though, that still needs a refresh of the page (maybe I need to do something to re-fetch the whole list, or do soft deletes).

Is your form and list on the same page?

Yes, but not on the same component. I have on the page the Cell which fetches and renders the data, then below it the button to add (which only opens the modal) and the modal with the form and the component. The cell renders a component (defined) and passes down the results of the fetching query as a prop to Success (as explained in the tutorial)

It doesn’t need to be the same component, updating the cache like mentioned above should work, if you return the correct stuff.

For me Apollo Cache is Your Friend, If You Get To Know It (2023) was really helpful.

I would usually recommend just updating the cache (as that doesn’t hard reload data, so you can animate and stuff), but there is also refetchQueries which you can hand some query to and it will reload whatever data.

We have similar pages with a Redwood Cell structure that renders a table of teams and a button to add a new item. The button opens a modal which contains a Redwood form.

In the Success state of the Redwood Cell we can add refetch as an input:

import type { FindItems, FindItemsVariables } from 'types/graphql'

import type { CellSuccessProps, CellFailureProps } from '@redwoodjs/web'

export const QUERY = gql`
  query FindItems() {
    items: items() {

export const Loading = () => (
  // table skeleton loading component

export const Empty = () => {
  <div className="flex items-center justify-center">No items found</div>

export const Failure = ({ error }: CellFailureProps) => (
  <div className="rw-cell-error">{error?.message}</div>

export const Success = ({ item, refetch }: CellSuccessProps<FindItems, FindItemsVariables>) => {
  // table component and other stuff

Now you can pass the refetch to your button or modal and what we do in our form is to make it part of the useMutation:

import { useMutation } from '@redwoodjs/web'
import { toast } from '@redwoodjs/web/toast'

const ADD_NEW_ITEM = gql`
  mutation AddNewItemMutation($input: AddItemInput!) {
    addItem(input: $input) {

const AddNewItem = ({ ..., setIsModalOpen, refetch }: Props) => {
  const [addNewItem] = useMutation(ADD_NEW_ITEM, {
    onCompleted: () => {
      toast.success('New item was added successfully')

In some other usages we get refetch from useQuery like:
const { loading, error, data, refetch } = useQuery(QUERY, { variables: { ... } }) and in some more complex patterns we wrap the refetch in a React.useRef() and pass the hook to the child component(s).

1 Like

Thank you for answering.
I did not quite understand where does the refetch() function come from

Does refetchQueries address this? Creating a Comment Form | RedwoodJS Docs