morrys / wora

Write Once, Render Anywhere. typescript libraries: cache-persist, apollo-offline, relay-offline, offline-first, apollo-cache, relay-store, netinfo, detect-network
https://morrys.github.io/wora/docs/introduction
MIT License
174 stars 4 forks source link

Trouble seeing queued mutations and connection state #81

Closed robnewton closed 3 years ago

robnewton commented 3 years ago

@morrys In our first attempts to use ApolloOffline we are simply trying to understand the correct usage with some simple boiler plate to show connection status and whether there are any mutations currently in the queue. Our code below is our attempt to do this but while it seems to be functioning, the status information doesn't appear correct and the callback event functions aren't called when the mutations finally do execute.

Any advice on how we can get some of these things working would be appreciated. If you have a more complete React Native example with this type of basic implementation you can point us at too, that would be helpful I think.

Our test consists of a couple on screen buttons:

Here's our test steps:

  1. On Mac OS connect to wifi and run the React Native app in the iOS simulator
  2. Page loads with the results of the query showing on the screen in the simulator
  3. Use a tool to completely disconnect the mac from the internet
  4. Hit the RN button that calls the checkMorrys() function
  5. React state is updated with online status which is still "Online".
  6. Hit the RN button to perform a mutation while offline
  7. Hit the RN button that calls the checkMorrys() function again to see storeOffline.getState() and storeOffline.getListMutation() get written to the console as empty for both (but we expected to see the one mutation in the offline mutation queue here)
  8. Morry's is still reporting online but we believe the mutation was queued successfully despite our inability to see it.
  9. Reconnect the mac to the internet
  10. Expect to see the online state change when this happens but since it was showing online the whole time again, going back online in reality doesn't have any affect on this.
  11. Expect to see the onExecute() function get called but it does not
  12. Expect to see the mutation performed on the server which we DO SEE which tells me all is working as expected, but we just can't get accurate insights into the internals.
  13. We hit the RN button to refresh the data on screen by calling the query again and it now shows the correct data from the server with the additional rows we mutated while offline.

Our app.js...

const client = new ApolloClient({
  link: httpLink,
  cache: new ApolloCache({
    dataIdFromObject: (o) => o.id,
  }),
});

client.setOfflineOptions({
  manualExecution: false, //optional
  link: httpLink, //optional
  start: async (mutations) => {
    //optional function that is called once the request queue has been started
    console.log('start offline', mutations);
    return mutations;
  },
  finish: async (mutations, error) => {
    //optional function that is called once the request queue has been processed
    console.log('finish offline', error, mutations);
  },
  onExecute: async (mutation) => {
    //optional function that is called before the request is sent to the network
    console.log('onExecute offline', mutation);
    return mutation;
  },
  onComplete: async (options) => {
    //optional function that is called once the request has been successfully completed. Only if the function returns the value true, the request is deleted from the queue
    console.log('onComplete offline', options);
    return true;
  },
  onDiscard: async (options) => {
    //optional function that is called when the request returns an error. Only if the function returns the value true, the mutation is deleted from the queue
    console.log('onDiscard offline', options);
    return true;
  },
  onPublish: async (offlinePayload) => {
    //optional function that is called before saving the mutation in the store
    console.log('offlinePayload', offlinePayload);
    return offlinePayload;
  },
});

export default function App() {
  client.hydrate();

  const [showAdd, setShowAdd] = useState(true);
  const [hydrated, setHydrated] = useState(false);
  const [online, setOnline] = useState(false);
  const [cache, setCache] = useState('');

  const checkMorrys = async () => {
    const storeOffline = client.getStoreOffline();
    const cacheState = storeOffline.getState();
    const cacheList = storeOffline.getListMutation();

    setHydrated(client.isRehydrated());
    setOnline(client.isOnline());
    setCache(JSON.stringify(cacheState, null, 2));

    console.log('Offline queue: ', storeOffline);
    console.log('Cache state: ', cacheState);
    console.log('Cache list: ', cacheList);
  };
morrys commented 3 years ago

Hi @robnewton, to subscribe to the offline store I suggest you read my answer in another similar issue: https://github.com/morrys/wora/issues/57#issuecomment-651324974

While for the connectivity problem I suppose this is a known problem of the netinfo library: https://github.com/react-native-netinfo/react-native-netinfo#issues-with-the-ios-simulator

robnewton commented 3 years ago

Thanks for the quick response. We will take a look at those two things.

robnewton commented 3 years ago

@morrys I wonder how the mutation is being cached correctly if the simulator is improperly reporting online. Does ApolloOffline have an internal check that is more robust that could cause the isOnline() function to return true but still know to queue the mutation inside?

robnewton commented 3 years ago

@morrys onPublish() which is recommended by you in the other issue to get queued mutation alerts is not being called when a mutation is added to the queue for us. We never see that function get called at all despite the offline mutation actually works. Could this be related to the iOS simulator failing to show the online state correctly?

robnewton commented 3 years ago

@morrys We just tried the following expecting a console log of the subscription call but we never get anything in the console.

  useEffect(() => {
    const dispose = client.getStoreOffline().subscribe((state, action) => {
      console.log('Offline mutation added: ', state, action);
      setOfflineMutationCount(state.length);
    });
    return () => {
      dispose(); // Make sure we unsubscribe when we're unmounted
    };
  }, []);
morrys commented 3 years ago

If the onPublish function is not called it means that the mutation is not performed in offline mode but online. This problem is due to the iOS simulator

robnewton commented 3 years ago

Ok that makes sense, thank you @morrys for the help