Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update useUpdate to use react-query #6891

Merged
merged 25 commits into from
Nov 25, 2021
Merged

Update useUpdate to use react-query #6891

merged 25 commits into from
Nov 25, 2021

Conversation

fzaninotto
Copy link
Member

@fzaninotto fzaninotto commented Nov 22, 2021

  • [BC Break] update useUpdate signature
  • pessimistic mode
  • optimistic mode
  • undoable mode
  • hook time and calltime parameters and options
  • Add unit tests
  • [BC Break] Update useEditController to use it
  • [BC Break] Removed deprecated <Edit successMessage> prop
  • [BC Break] Update onSuccess and onFailure callbacks props and signature for <Edit> and <SaveButton>
  • Fix tests
  • Add upgrade instructions
  • Update demos
  • Update documentation

It turns out react-query's handling of cache, invalidation and stale queries is completely backwards in comparison with http logic, so this was not a piece of cake. I'm not sure we end up with less code to maintain than with our current Redux implementation.

import { useUpdate } from 'react-admin';

const IncreaseLikeButton = ({ record }) => {
    const diff = { likes: record.likes + 1 };
    const [update, { isLoading, error }] = useUpdate();
    const handleClick = () => {
        update('likes', { id: record.id, data: diff, previousData: record })
    }
    if (error) { return <p>ERROR</p>; }
    return <button disabled={isLoading} onClick={handleClick}>Like</div>;
};

@fzaninotto fzaninotto added the WIP Work In Progress label Nov 22, 2021
@@ -28,19 +28,7 @@ export const doQuery = ({
store,
mutationMode,
}: DoQueryParameters) => {
const resourceState = store.getState().admin.resources[resource];
if (canReplyWithCache(type, payload, resourceState)) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to disable application cache because it's incompatible with react-query. React-query gives an equivalent, albeit not controlled by the server. It's a BC break we should accept IMO, as application cache is a minor feature not widely used.

...old,
...data,
}),
{ updatedAt }
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not happy with this one but I didn't find any better solution

);
};

let context: { previousGetOne?: any; previousGetList?: any } = {};
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the job of the onMutate callback to set the context normally, but I actually need to define it beforehand (in the mutate wrapper), so I'm using this closure.

data: callTimeData = data,
} = variables;

// optimistic update as documented in https://react-query.tanstack.com/guides/optimistic-updates
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The react-query doc advises to do this in onMutate, but in that case it's impossible to fire the success side effects right away. I had to use a wrapper for mutateAsync (and therefore mutate) instead.

Besides, the wrapper was necessary for the undoable mode, which shouldn't call the mutate callback until the action is confirmed.

@fzaninotto fzaninotto added RFR Ready For Review and removed WIP Work In Progress labels Nov 23, 2021
@fzaninotto
Copy link
Member Author

And we're Ready For Review!

@fzaninotto fzaninotto mentioned this pull request Nov 24, 2021
Copy link
Collaborator

@djhi djhi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work

packages/ra-core/src/dataProvider/useUpdate.ts Outdated Show resolved Hide resolved
packages/ra-core/src/dataProvider/useUpdate.ts Outdated Show resolved Hide resolved
> = {}
) => {
if (mutationMode === 'pessimistic') {
return mutation.mutateAsync(variables, callTimeOptions);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, we don't merge the declaration time options with the calltime ones?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is done by the mutation callback (the first argument of useMutation)

return mutation.mutateAsync(variables, callTimeOptions);
}

const { onSuccess, onSettled, onError } = callTimeOptions;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We ignore the declaration time options?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, they're taken care of by the useMutation callback

});
} else {
// undoable mutation: register the mutation for later
undoableEventEmitter.once('end', ({ isUndo }) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can we be sure this event was dispatched for this specific query? What if there are multiple queries sent in a short timeframe?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't. That's the way it'as always worked.

But it's not a real problem as, in order to perform a new mutation, users have to click somewhere, which dismisses the MUI Notification and commits the initial update.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. That's only true for our implementation of the ui though

@djhi djhi merged commit 3c6fa9d into next Nov 25, 2021
@djhi djhi deleted the react-query-update branch November 25, 2021 08:49
@fzaninotto fzaninotto added this to the 4.0.0-alpha.1 milestone Dec 6, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
RFR Ready For Review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants