Data not reloaded properly

Hi there,
I am currently facing an issue with some data that i am updating but that are not reloaded properly for display.

I have users and restaurants in the DB. A user has a restaurant.
Here is an extract of the schema :


model User {
  id                    Int     @id @default(autoincrement())
  created_at            DateTime? @default(now())
  restaurant            Restaurant? @relation(fields: [restaurantId], references: [id])
  restaurantId          Int?
  ...
}

model Restaurant {
  id              Int     @id @default(autoincrement())
  created_at      DateTime? @default(now())
  name            String
  ...
}

I have simplified the workflow but basically, i have 2 pages, a first one on which i display the current user restaurant name, and a second page on which i have a cell that calls a query that updates the restaurant name and navigate back to the first page.

When navigating back to the first page, the restaurant name displayed is not correct and i have to refresh my browser page to see the changes.

On the first page i am getting the user and its restaurant using :
import { useAuth } from '@redwoodjs/auth'
and
const { currentUser } = useAuth()
{currentUser.restaurant.name}

I navigate to the second page using navigate function from the redwoodjs router:
import { navigate, routes } from '@redwoodjs/router'

In the second page, and in the cell i use an api service to update the user restaurant name and navigate back to the first page also by using navigate function.

Would you have an idea how to reload the user data (the restaurant) automatically so that they are displayed correctly right away?
I have tried navigating back to the first page using document.location.href method and it’s working fine but i would prefer to keep using the router.

Thanks for your help.
Didier

Howdy!

In your getCurrentUser() function are you returning the list of restaurants at the same time? It sounds like Redwood might be “caching” that data (so that it doesn’t have to go all the way back to the auth provider for each and every component update that references currentUser).

You could try, after your mutation, to re-authenticate the user. There’s an onCompleted option you can pass to useMutation which will be called once the GraphQL call is all done. In there you can call reauthenticate() (which is another function you can destructure from useAuth()). That’ll get Redwood to refresh the data for currentUser, which would include the attached child records like restaurant.

const { reauthenticate } = useAuth()

const [updateRestaurant, { loading, error }] = useMutation(
  UPDATE_RESTAURANT, 
  { onCompleted: reauthenticate }
)

Let us know if that works!

Another option @berliozd you may consider:

  • Don’t include and return the user’s profile (ie, restaurants) on the currentUser and reduce the heft of the getCurrentUser since that really just needs to basic info + roles
  • Create a profile service that queries and updates the user’s profile, ie as part of updateProfile it sets their restaurants
  • Then in you cells, you can query and mutate the profile rather that relying on currentUser to keep all that info

Remember that getCurrentUser is called often, so any additional work it has to do is well … more work and if you only need to show restaurants in certain pages you can fetch those as needed. But currentUser can still have basic things like name and avatar that could be seen throughout.

Also, just be sure to refetch after a mutation.

Thanks @rob. Thanks for your quick reply. Unfortunately it doesn’t seem to work any better. I had to rewrite a little bit my code as i was using a cell and i wasn’t sure how i could implement the onCompleted option with it. So I directly used a mutation in my page. I can see the graphql call __REDWOOD__AUTH_GET_CURRENT_USER but the restaurant name doesn’t reflect the changes in DB. I would also say that even without the reauthenticate i can see the graphql call the same way with the same result. There is for sure some caching on the user data which is fine for performance but i am wondering how we could invalidate this cache.

Thanks @dthyresson, i might think of that solution as a seond option if i cannot fix it without changing too much things. And you are right, it might a good idea to separate these additional info.

This is why we have the restaurant called with the getCurrentUser, a user can only have one restaurant in the current stage of our project.

@dthyresson your solution sounds safe & secure, but it leaves us wondering why __REDWOOD__AUTH_GET_CURRENT_USER’s cache isn’t refreshed as one would expect.

@rob is it by design?

Sounds like we need a small reproducible example.

Perhaps two pages with auth and a cell and a random number from nanoId is set on the current user and the page and cell show that value.

And have a mutation see what they values are — the number value should always change and be different, right?

currentUser is cached on the client-side in memory. If you want to update the currentUser you can call reauthenticate

const { currentUser, reauthenticate } = useAuth()
useEffect(() => reauthenticate(), [])
// currentUser will update and it'll be refreshed.

I would consider this an anti-pattern.

1 Like

It is, so that we don’t have to go back to the auth provider and/or database to get data each time useAuth() is invoked.

However, calling reauthenticate() will force the backend to go back to the provider/db to get the auth data again. It’s very strange that it didn’t work for you…is it possible that your reauthenticate() call actually happened before the mutation was completed and the data was updated in the database?

You said " i was using a cell and i wasn’t sure how i could implement the onCompleted option with it" but Cells only query data automatically for you. If you want to change any data you need to manually add a useMutation() call (which is where the onCompleted goes). How were you changing the restaurant record without calling useMutation originally?

1 Like

I have tried calling reauthenticate in both pages, first in the page where i call the mutation in the onCompleted like this :

  const _onCompleted = () => {
    reauthenticate().then(navigate(routes.restaurateurShare()))
  }

  const [updateRestaurant] = useMutation(UPDATE_RESTAURANT, {
    onCompleted: _onCompleted,
  })

But also in the page i am redirected to (and where i would like to see the updated changes) :

const SharePage = () => {
  const { currentUser, reauthenticate } = useAuth()

  useEffect(() => reauthenticate(), [])
...
return (
    <Layout>
      {currentUser.restaurant.name}
...

But it doesn’t work unfortunately… It still see the old restaurant name and have to hit refresh.

I have noticed that if i remove the navigate to routes.restaurateurShare() using navigate after the mutation but just stays on that page and go to the first using a <Link to={routes.restaurateurShare()} /> (by clicking it), then in that case on the restaurateurShare page, i will see the new data.

@rob, i was doing it in the Query which, I know, is not a really good practice.

After finding this I wanted to post the solution.
You need to await the reauthenticate() call!

I also originally missed this :slight_smile:
So:

const { reauthenticate } = useAuth()

const [updateRestaurant, { loading, error }] = useMutation(
  UPDATE_RESTAURANT, 
  { onCompleted: async () => {
      await reauthenticate()
      navigate(routes.someRoute())
    } 
  }
)