React component not re-render after cache.modify/cache.writeQuery

const [createAssetMutation, createAssetMutationResult] = useMutation(
    CREATE_ASSET_MUTATION,
    {
      update(cache, result) {
        cache.modify({
          id: "Project:" + projectId,
          fields: {
            assets: (previousData, { toReference }) => {
              return [...previousData, toReference(result.data.createAsset)];
            },
          },
        });
      },
    }
  );

I have a mutation that creates asset inside project, i wanted to add the created asset inside project assets field in cache. I tried to do that cache is updated but the component not re-rendered.

Can anyone help me how to proper write the new data to cache and re-render the component?

Can you show the code of the component that is not rerendering?

i’m using lazyQuery

  const [fetchProjectAssets, { data, error, refetch }] = useLazyQuery<
    SingleProjectQueryGqlResponse,
    SingleProjectQueryGqlVariable
  >(SingleProjectQueryGql);

Please show the full component, as well as the queries, not just the variable names. It’s really hard to get a full picture with this little information.

Here is the component

export default function Projects() {
  const [fetchProjects, { data }] = useLazyQuery<
    UserProjectsQueryClientGqlResponse,
    UserProjectsQueryClientGqlVars
  >(UserProjectsQueryClientGql);

  const [projects, setProjects] = useState<Partial<DashboardProject>[]>([]);
  const { setPageFilterConfigs } = useFilters();

  useEffect(() => {
    //setting projects
    if (data?.projects) {
      setProjects(data.projects);
    }
  }, [data?.projects]);

  useEffect(() => {
    //this filter config is runs first time automatically when the page is loaded
    //this is for filter configs
    setPageFilterConfigs(FilterTypes.dashboard, {
      fetch: (variables) => fetchProjects(variables),
      searchStringVariable: "searchKeyword",
      //default variables
      defaultVariables: {
        states: ProjectStateEnum.Active,
      },
    });
  }, []);

  return (
    <div className="main-wrapper">
      {projects?.map((project) => (
        <div key={project.id} className="project-container">
          <h1>{project.name}</h1>
          <div className="assets">
            {project.assets?.map((asset) => (
              <div key={asset.id}>{asset.name}</div>
            ))}
          </div>
        </div>
      ))}
    </div>
  );
}

Query:


const UserProjectsQueryClientGql = gql`
  query UserProjectsQueryClient(
    $searchKeyword: String = ""
    $states: [ProjectStateType!]
  ) {
    projects(
      where: {
        AND: [
          {
            OR: [
              { name: { contains: $searchKeyword, mode: insensitive } }
              {
                assets: {
                  some: {
                    name: { contains: $searchKeyword, mode: insensitive }
                  }
                }
              }
            ]
          }
          { OR: [{ state: { in: $states } }] }
        ]
      }
      orderBy: [{ name: asc }]
    ) {
      id
      name
      assets(orderBy: { position: asc }) {
        id
        name
      }
    }
  }
`;

Just to make sure it isn’t caused by that useEffect+useState combination, could you please replace that with

const projects = data?.projects || EMPTY_ARR;

where EMPTY_ARR is a constant you define above your component like

const EMPTY_ARR = []

?

That is pretty much equivalent, but saves you one unnecessary rerender.

Also, if I might ask: how do you determine if the component rerenders? Have you placed a console.log(projects) inside the component?

I have checked by doing the way you have told me, but didn’t work. if i return empty array from the cache modify then the component re-rendered, but whenever i’m adding new array with items it is not working.

re-rendered for this code

cache.modify({
          id: "Project:" + projectId,
          fields: {
            assets: (previousData, { toReference }) => {
              return [];
            },
          },
        });