简体   繁体   中英

How do you effectively batch GraphQL mutations using Apollo Client?

I'm having an issue handling rapid database updates using GraphQL mutations, specifically through useQuery and useMutation from Apollo Client's react-hooks . I have a table which represents data from the DB, 4 columns are boolean values represented by checkboxes, with other inputs as well. Checking the checkbox dispatches a request to the database to set the value to true, then refetches (either through refetch imperatively or refetchQueries ) the query and updates the table.

My Checkbox component:

export const TableCheckbox: <T extends VasaRecord & DomainEntity, K extends keyof T>(props: TableInputProps<T, K>) => ReactElement = ({
  value, // Boolean column value
  record, //Entire data record
  dataIndex //Accessor on record where value is located
}) => {
  const [checked, setChecked] = useState<boolean>(value as boolean);

  // useMutation function
  const { updateEntity } = useContext(
    TrackerContext
  );

  useEffect(() => {
    setChecked(value as boolean);
  }, [value]);

  const handleCheck = (e: CheckboxChangeEvent) => {
    const val = e.target.checked;
    setChecked(val);
    const newRecord = { id: record.key, [dataIndex]: val };

      updateEntity({
        variables: { entityTracker: JSON.stringify(newRecord) }
      }).then((res: any) => {
        console.log(res);
      });

  };

  return (
    <span className="checkbox-wrapper" onClick={disableClickSelect}>
      <Checkbox checked={checked} onChange={handleCheck} />
    </span>
  );
};


However, this cycle can take 1-2 full seconds, which is not a usable response time to see a change reflected. I've addressed this by managing the checkbox state internally and updating it before the mutations/queries are processed and the new data returned.

This mostly works fine, but causes strange behavior when checkboxes or inputs etc. are updated very quickly in succession and some updates can be missed as their requests are not fired. Even worse, because I'm managing the state on the front end, it can show inaccurate information that's then overwritten when the last query returns. I could disable the inputs while a request is running, but that feels like cheating. It's not really noticeable unless you're specifically trying to use tab and space to check as fast as humanly possible, but still isn't good.

Is the answer using the in-memory cache provided by Apollo to store the data clientside so it can be updated instantly? This sounds like it could work, but I wonder if I would have the same problem if updates are dispatched so rapidly that they interfere with one another, plus it would mean rewriting all of the code for interacting with the database everywhere, even where this is not an issue (unless I'm mistaken), so I'd rather avoid it if possible.

Is there an effective way to batch mutations or otherwise prevent them from interfering with each other? Is my entire approach flawed? This pattern works fine when updates are triggered individually or by a user action, but it doesn't seem to handle real-time updates well at all, so any insight or alternatives are much appreciated!

It sounds like you should take advantage of Apollo's optimistic UI features . You can specify an optimisticResponse for your mutation which will be used as a placeholder for the actual response from the server. This allows your UI to smoothly change in response to user actions even when it takes a while to get a response from the server. The optimistic response is applied to the cache itself, so any other part of your app will immediately reflect the mutation as well. Unfortunately, it will not work with refetch , but ideally you should be using update instead of refetching queries anyway (and optimisticResponse does work with whatever update logic you provide).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM