Twisterking / meteor-graphql-test

MIT License
0 stars 0 forks source link

Problems with finalizing Mutations while offline #1

Open Twisterking opened 4 years ago

Twisterking commented 4 years ago

Some help needed!

In Itemlist.jsx I do the following mutation:

const [addToCart, result] = useMutation(ADD_TO_CART, {
  update(cache, { data: { addToCart } }) {
    const { openorderbody } = cache.readQuery({ query: GET_CART_DATA, variables: { groupId: 'vXGNoPBx5cxDbMsui' } });
    const newOpenOrderBody = openorderbody.concat([addToCart]);
    console.log('Mutation update()', { addToCart, newOpenOrderBody }); // is logged also while offline
    cache.writeQuery({
      query: GET_CART_DATA,
      data: { openorderbody: newOpenOrderBody },
    });
  },
  optimisticResponse: {
    addToCart: {
      __typename: "OpenOrderElement",
      list_id: "aqMMFbWYu6zary74i",
      itemId: "Sd2irqR9PXm6pXKes",
      item_amount: 19,
      row_id: 77,
      unit: "kg",
      _id: Random.id()
    }
  },
  onError(err) {
    console.error('Mutation Error:', err);
  },
  onCompleted(data) {
    console.log('Mutation Completed. Data:', data);
  }
});
console.log('Mutation result?', result); // result is stuck at result.loading: true while offline

Any ideas on how to achieve finalizing the mutation even while offline?

morrys commented 4 years ago

Hi @Twisterking, if you are interested I have created this library wora/apollo-offline which enables apollo applications to be used offline.

let me know if you need help

Twisterking commented 4 years ago

Hey @morrys thanks a lot! I will give it a try! In your examples you always use a HTTP link. In my meteor app I am using the https://github.com/Swydo/ddp-apollo as my main link - any idea if it should also work with this one?

morrys commented 4 years ago

I didn't do a real test with this link because the library is agnostic to the link used, rather it allows to configure different links for online and offline executions.

Twisterking commented 4 years ago

I see :) I just had a look, looks nice! Just one thing/improvement/question: How do you detect, if a user is offline? My experience shows, that you should actually detect, how slow a internet connection is and flag a user/connection as offline a lot earlier than when he is completely offline. So how do you detect if a connection is offline?

basically something like this: https://stackoverflow.com/questions/5529718/how-to-detect-internet-speed-in-javascript

const arrTimes = [];
let i = 0; // start
const tThreshold = 150; //ms
const testImage = "http://www.google.com/images/phd/px.gif"; // small image in your server
const dummyImage = new Image();

function testLatency(cb) {
  let tStart = new Date().getTime();
  dummyImage.src = testImage + '?t=' + tStart;
  dummyImage.onload = function() {
    let tEnd = new Date().getTime();
    let tTimeTook = tEnd-tStart;
    arrTimes[i] = tTimeTook;
    i++;
    let sum = arrTimes.reduce(function(a, b) { return a + b; });
    let avg = sum / arrTimes.length;
    // TODO: Check if current val is way lower than the last --> online again
    // TODO: Check if current val is way higher than the last --> OFFLINE
    cb(avg);
  }
}
morrys commented 4 years ago

To manage the network, I created this library https://morrys.github.io/wora/docs/netinfo. The library allows information on network quality to be detected but I do not agree that it is the optimal solution to define when an application is offline, because you could simply have a short period of slow connection.

However, the theme is certainly interesting and it would be more appropriate to open a issue in the repository in order to be able to evaluate the management or the alternative solution (there are several solutions to discuss):)

these themes are also of interest for applications in relay contexts.

Twisterking commented 4 years ago

So I just tried implementing your apollo-offline package, and my Queries aren't even called any more 😢 - I thought just replacing the ApolloClient with yours would "just work", at least while being online, and not break anything ...

Also: client.hydrated is not a function?!

anything wrong here @morrys?

import { ApolloClient } from "@wora/apollo-offline";
import ApolloCache from '@wora/apollo-cache';
import { DDPLink } from 'meteor/swydo:ddp-apollo';

const ddpLink = new DDPLink();

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

Meteor.startup(async () => {
  // wora
  // await client.hydrated(); // first error!

  // fake offline:
  // Meteor.disconnect();

  render(
    <ApolloProvider client={client}>
      <App />
    </ApolloProvider>,
    document.getElementById('react-target')
  );
});

EDIT 2: Okay I guess you meant await cache.hydrate() - but still: my subscriptions are called, but the normal graphQL queries which should obviously be called at least once are never called -> no data. :/

  const { loading, error, data } = useQuery(GET_USER_DATA, {
    variables: { userId: 'seDueMBtGiuMCWez6' },
  });
  console.log({ loading, error, data }); // loading: false, error: undefined, data: undefined

Branch: https://github.com/Twisterking/meteor-graphql-test/tree/v0.2.1

morrys commented 4 years ago

This is the functionality to call https://github.com/morrys/offline-examples/blob/master/apollo/todo/client/src/app.js#L74-L81 this allows you to perform both the cache restore and the connection check and its subscription to the network detection.

Twisterking commented 4 years ago

well this part of the code is basically only displaying an empty <div/> while hydrating. that's not really the problem. again, my queries are for some reason never called. Maybe you can kindly take a look? 😄 https://github.com/Twisterking/meteor-graphql-test/tree/v0.2.1

morrys commented 4 years ago

put client.hydrate() here: https://github.com/Twisterking/meteor-graphql-test/blob/v0.2.1/client/main.jsx#L72

I saw the branch but there is wora commented :)

When you start the application without the restore it is considered offline

Twisterking commented 4 years ago

Okaayyyy now I am getting somewhere! 😄 Now I just need to figure out how to update my subscription in Cart.jsx when I add an item via Mutation in Itemlist.jsx while being offline.

https://github.com/Twisterking/meteor-graphql-test/blob/v0.2.1/imports/ui/Itemlist.jsx#L80 is fired, but at the same time the Cart.jsx is not updating.

morrys commented 4 years ago

I see that in this part of the code https://github.com/Twisterking/meteor-graphql-test/blob/v0.2.1/imports/ui/Itemlist.jsx#L80 the optimumResponse is commented, this is the version with which have you tried?

I want to clarify that for a correct works offline, there are two aspects to consider:

morrys commented 4 years ago

hi @Twisterking, check this cache configuration: https://github.com/Twisterking/meteor-graphql-test/blob/v0.2.1/client/main.jsx#L73

This configuration is the same as the apollo inMemoryCache (in my example project it was set up like this) https://www.apollographql.com/docs/react/caching/cache-configuration/#configuring-the-cache

Twisterking commented 4 years ago

Thanks a bunch for your help @morrys ! I think I am making progress here! 😄

Unfortunately offline mutations still seem to not work properly. Please see here: https://github.com/Twisterking/meteor-graphql-test/blob/v0.2.1/imports/ui/Itemlist.jsx#L106-L129 Is there anything wrong here?

After firing one of these <Mutation>s, I can see a bunch of console.logs coming from here:

const cache = new ApolloCache({
  dataIdFromObject: o => {
    console.log('dataIdFromObject o:', o);
    return o._id
  }
});

But still, my GET_CART_DATA/SUB_CART_DATA query/sub in my Cart.jsx component is NOT updating and showing the added cart item. Any idea why? 😢

When I am online, everything works just fine and Cart.jsx is updating properly!

morrys commented 4 years ago

Hi @Twisterking, to answer you precisely I should try your project but I don't think I can try it before the weekend 😌

anyway try to take a look here: https://github.com/Twisterking/meteor-graphql-test/blob/v0.2.1/imports/ui/Itemlist.jsx#L114

I see you do readQuery with variables and write without, is it wanted?

Twisterking commented 4 years ago

Thanks so much my friend!! --> https://github.com/Twisterking/meteor-graphql-test/commit/84082302b64da0664f16b1eb65b3e1718ba01b64 Thanks to you I think I understand much more now! One last thing: is this the proper way to do this? -> https://github.com/Twisterking/meteor-graphql-test/blob/v0.2.1/imports/ui/Itemlist.jsx#L112 Or is there a more elegant way? Without this line, I am getting a duplicate key (_id) error.

morrys commented 4 years ago

hi @Twisterking, this is strange, simply by reading the code I cannot understand how there can be two identical identifiers.

can you give me some more info? As soon as I can I will make the clone of the project :)

Twisterking commented 4 years ago

hmm well .. I am creating my new _id with Random.id() on the client, send it to the server, which takes the _id and all the other attrs and inserts the OpenOrdersBody element. it then also returns it. for some reason this gets also inserted into the local cache after the roundtrip, which results in a duplicate _id.

morrys commented 4 years ago

Reading the code it seems to me that there are two elements that share the same ID but are different types right? type ListElement { _id: ID, type OpenOrderElement { _id: ID,

morrys commented 4 years ago

Hi @Twisterking , could you give me some indications of how to run your example project? :)

Twisterking commented 4 years ago

Oh sorry I didn't reply here. The problem was something completely different! Please check the current source! I only created a Random-id() on render() of the <li> element - now I do it every time the mutation is called as it should be. Works like a charm now. Thanks so much for your help mate!!

morrys commented 4 years ago

great :) I advise you to follow the repository that a new release will soon be released and having feedback for me is important :) https://github.com/morrys/wora/issues/29

Twisterking commented 4 years ago

Great! Just subscribed!