10

In a react login component, I'd like to refetch and update the navbar component once login is successful.

const loginUser = () => {
    props.mutate({
      variables: {
        input: { email, password },
      },
      refetchQueries: [{ query: GET_ME }],
    });
  };

I can see the login and re-fetch in network tab, and both return 200 with proper status. But the navbar still displays the old data.

Here is my navbar component.

export const Header = props => {
  return <div>Header {JSON.stringify(props.data)}</div>;
};

export default graphql(GET_ME)(Header);

And apolloClient:

export const client = new ApolloClient({
  link: createHttpLink({
    credentials: 'include',
    uri: 'http://localhost:8080/api/graphql',
  }),
  cache: new InMemoryCache(),
});
leogoesger
  • 3,476
  • 5
  • 33
  • 71

4 Answers4

9

Try adding

 options: {
      awaitRefetchQueries: true
 },

to your props.mutate next to refetchQueries and variables.

Queries refetched using options.refetchQueries are handled asynchronously, which means by default they are not necessarily completed before the mutation has completed. Setting options.awaitRefetchQueries to true will make sure refetched queries are completed before the mutation is considered done (or resolved). options.awaitRefetchQueries is false by default.

John Franke
  • 1,444
  • 19
  • 23
  • this may have solved the problem for me, but what i did was something different by using fetchPolicy and errorPolicy – leogoesger Dec 07 '18 at 06:28
0

What John said could be the solution to some people, but it wasn't mine.

For me, it is pretty typical to get a return of nothing or an error when query getMe if user isn't logged in.

Because of that, the next call will not reset the cache, which bugs out the entire system.

The solution to my problem was giving an errorPolicy of none.

export const isAuth = compose(
  graphql(GET_ME, {
    options: {
      fetchPolicy: 'cache-first',
      errorPolicy: 'ignore',
    },
  })
);

Since I am using HOC, this is my solution.

leogoesger
  • 3,476
  • 5
  • 33
  • 71
0

I encountered a problem where the data from the useQuery hook was not updating after calling the refetch function. In my case, the cause of the problem was the onError callback. Removing this and using a useEffect hook to watch the error variable fixed the issue.

const { data, loading, refetch } = useQuery(GET_LIST, {
    variables: {
        offset: 0,
        limit: 50,
    },
    onError: () => {
       // handle error here
    },
})

Change to:

const { data, loading, refetch, error } = useQuery(GET_LIST, {
    variables: {
        offset: 0,
        limit: 50,
    },
})

useEffect(() => {
    if(error){
        // handle error here
    }
}, [error])

laij84
  • 261
  • 2
  • 8
0

Looking at GitHub issues about this, it appears there may be a bit of a glitch in refetch. In my case it put the latest data in the cache, but did not trigger a React refresh.

Here's how I solved it:

const loading = useRef(false);
const dataToDisplay = useRef([]]);
const [toggleRefresh, setToggleRefresh] = useState(false);

useEffect(() => {
    loading.current = true;
    client.query({
        query: MY_QUERY,
        variables: {"myVar": myVar},
        fetchPolicy: 'network-only',
        skip: loading.current
    }).then((result) => {
        loading.current = false;
        dataToDisplay.current = result.data.dataToDisplay;
        setToggleRefresh(!toggleRefresh); //cheesy but it seems to work
    });
}, [varThatTriggersRefetchWhenChanged]);

You might say, "But that doesn't make sense. skip is set to loading.current, and loading.current has to be true at that point."

Based on other SO posts, I think the new value for a useRef may not be there until the next render.

VikR
  • 4,818
  • 8
  • 51
  • 96