Apollo useQuery stuck in loading = true condition after offline mutation - apollo

16m
I am trying to complete a robust offline React, PWA using Apollo.
I have a functional component that uses useQuery to retrieve a list of items. It is using the default fetchPolicy. When this component renders, it successfully retrieves the data. If I am online or offline it works just fine.
If I am offline and I make a call to useMutation to create a new item, the list updates correctly, since I am using optimisticResponse and the update feature of mutations.
The problem happens when I navigate away from the list component, so that it is no longer rendered, then I return. Upon returning, the functional component that list all of the items is rendered again, it is stuck in the loading=true condition since I invoked the mutation. All this time the app is still offline. While in this loading state, I try to create another item while offline. The list never optimistically updates in this situation.
What do I have to do to get this to work? Is there a fundamental flaw to my basic approach to making this an offline-first app?
Here is a summary of the steps that create the problem.
Functional component executes a query and retrieves a list of items and renders them without issues.
Place the app offline.
While the list component is still rendered, invoke a mutation to create a new item while offline.
Optimistically update the UI (by updating the cache) with no issues.
Navigate away from the list component.
Navigate back to the list component (forcing a rerender of the entire list component)
The list component useQuery/loading value is stuck in true condition.
Attempt to create another item the same way as before.
The list does not optimistically update.
I cannot seem to figure this one out.

Related

Ember Unit testing: counting new items rendering

I wrote a controller that holds a list, and by clicking a "get more" button, renders 5 more items of that list. I want to create some tests for that, and I want to validate that it only renders 5 more items (instead of re-rendering the entire list).
Is this even possible?
It very depends on what 're-rendering' is for you.
You can check if IDs of the old items were not changed and if their state is still valid. This was an issue that I have to solve by using Ember.ArrayProxy.
If you want to test if browser have to re-render it, you can try to count number of execution of 'init' method - https://guides.emberjs.com/v2.6.0/components/the-component-lifecycle/

Where to store transient UI state in Ember 2.0

Ember 2.0 has gone great lengths towards making everything a component. With routable components coming soon, controllers will probably phased out as well.
Context
However, there is a recurring problem I face when building User interface, which I don't have a satisfying pattern for so far: user interface state.
What am I taking about?
Selection state
Current focus
Folded/unfolded state in some tree display
Basically, any state that is not part of the actual data, yet has to be tracked on an object-by-object basis. In the past, this used to be done with Controllers, acting as proxies to models. This approach is now obsolete. The new approach is Components everywhere, for the better. Component does the bookkeeping, tracks transient state and you get actions back.
A typical pattern I have, though, is with shared state, such as a list with selectable items.
The issue
Building a list component, with the following requirements:
Each item can be selected.
Selection state changes the DOM (some class bindings).
User can draw a rectangle in the list component to select several items at once.
Ideally, the whole behavior can be abstracted out as a mixin.
Question: where does the selection flag live?
Attempts
1) Everything is a component.
I make each item a sub-component, say {{my-list-item}}. The component tracks the selection state. Problem: how can the list component update the selection state?
2) Move state out of sub-components.
Put it on the list component. Within a separate state array alongside the item list. Pros: the list has all the state it needs. Cons: it's a nightmare to keep it synced when items are added or removed from the list. And it means the sub-component have no access to the state. Or maybe I could pass it to them as a bound value?
3) Reintroducing proxies.
Coming to think of it, there is a way to share some state: put it on the models. Well, not on the actual models so as not to pollute them with local state, but by setting up an ArrayProxy that will return some ObjectProxy for every item, to hold the state.
Pros: this is the only solution I managed to implement completely. Cons: encapsulation and decapsulation of items is a hassle. Also, after a few layers of being passed around, get and set have to go through 4 ou 5 proxies, which I fear will be a problem with performance.
Also, it does not work well for mixins. Should I want to abstract out some HasSelection mixin, and a HasFoldableItems mixin, and a Sortable mixin, they all need some state.
Back to the drawing board
Is there some better pattern I have not found?
I found the following relevant questions, but that led me nowhere:
Ember.js - where should interface state be stored? (2012, suggests something close to my #3 above)
Road to Ember 2.0 - High level Ember app structure feedback? (some of the key questions in the list are relevant to this one)
Great question - I actually went to one of the core ember team members to find out and the answer currently is services. Because the component is best left stateless (for the most part) you can leverage a service to persist this state that doesn't fit into a server persisted model.
Here is a great example that Stef Penner put together showing how you might save a "email draft" in your ember app (that isn't persisted backend)
https://github.com/stefanpenner/ember-state-services
Example component for reference (from the github project above)
export default Ember.Component.extend({
tagName: 'form',
editEmailService: Ember.inject.service('email-edit'),
state: Ember.computed('email', function() {
return this.editEmailService.stateFor(this.get('email'));
}).readOnly(),
actions: {
save() {
this.get('state').applyChanges();
this.sendAction('on-save', this.get('email'));
},
cancel() {
this.get('state').discardChanges();
this.sendAction('on-cancel', this.get('email'));
}
}
});

stop meteor rerender every child template inside of each block when find query changes?

i'm rendering a list of elements based on a collection on the meteor server.
the elements are rendered using an #each block which is populated from a helper method that returns a cursor which is the result of a find query. in order to sort the list based on some attribute of its data i run a new find with a different sort option.
this works fine and the list is rendered in the desired order. the problem is meteor is rerendering each element.
now i have two problems:
1) the elements can contain an embedded video that is playing. this is reset when meteor rerenders the element
2) i want to have some css transitions animate the repositioning of the elements. since meteor rerenders every element in the dom, the css transitions don't work.
i was partially able to solve problem #1 using a constant block but problem #2 remains a mystery. i could do all the sorting and filtering client side without relying on meteor but that seems clumsy.
is there any way that meteor can just reposition the elements in the dom instead of removing and readding them?
in the documentation for renderList i found this (which makes it seem like meteor could at least theoretically do what i want):
renderList is more efficient than using Meteor.render to render HTML for a list of documents. For example, if a new document is created in the database that matches the query, a new item will be rendered and inserted at the appropriate place in the DOM without re-rendering the other elements. Similarly, if a document changes position in a sorted query, the DOM nodes will simply be moved and not re-rendered.

Update/Remove items in Ember Array

I'm doing prototype small app on emberjs for my project.
It's here - jsbin
I have a list of transactions, which are displayed to the user. User may update or delete some of it.
For example, after update - transaction general status must be change on "Done" if both user status is "Done" (see properties of App.Transaction model).
After "Remove" user action is simply remove from array :)
How it is correctly implemented in ember.js methodology with Ember Arrays?
P.S. Pay no attention to that transaction list is static, in the future I would use ajax-request on load of app for fill transaction list. Currently, statics is made for simplicity.
Thanks.
Here is your working jsbin.
I've changed a few things, instead of passing the id when updating a transaction we pass now the transaction itself, so you can call setProperties on it and set the general_status to Done. I've also changed this behavior when deleting a transaction. And when adding a transaction you where using always the same id which is not optimal, I've used Ember.uuid to get always on creation a new id for your new record.
Have a look at the changed code to see the changes.
As a side note I should mention that you overall approach is not quite following ember's conventions, but ember is flexible enough to make it work anyway :)
Let me know if this is what you where looking for.

Emberjs Handlebars #each helper slow when bound to computed properties

I'm running into a performance issue when I render a list of items using the #each helper or a collection view bound to some computed properties of an Ember.ArrayController. Performance is fine with a small list of 10 - 20 items, but around 50 - 100 it starts to lag quite noticeably. Try checking off a few todos or clicking "Add Todo"
Example code is here: http://jsfiddle.net/Jonesy/ed3ZS/4/
I noticed that the childViews in the DOM get re-rendered with each change, which could very well be the intended behaviour at the moment, but I'd prefer to be able to just have a todo be removed from the DOM of unfinished todos list individually and appended to the bottom of the finished todos list, which would in theory be much less costly.
What I'm hoping to have answered is whether am I looking at a performance issue with Ember collection views, or is displaying a list populated from a computed property a bad idea, and if so, will I need to manually manage the todo model's location in the view layer as it changes from unfinished to finished and vice versa.
This is a side-effect of how {{#each}} (and CollectionView, which is what powers it) works.
Internally, CollectionView uses something called array observers. An array observer allows you to subscribe to mutations made to an array when they are done using Ember.Array's mutation methods (replace, pushObject, popObject, etc.) The API for array observers is described here.
What this means is that, if you push a new object into a collection view, it will insert render one new element in the DOM and leave the rest in place.
In the example you posted, however, the array is not being mutated--you're creating a brand new Array object every time a new item is added or removed. When the binding synchronizes, it replaces the old array with the new array. To {{#each}}, this is no different than removing all of the elements and then adding them back in.
The solution to the problem is to use a single array, instead of a computed property that returns a different array object each time it changes. You can see the Contacts app for an example of how to do this.
Obviously this is a very common pattern, and we'd like to add some kind of filtering that does the right thing by default to Ember.ArrayController down the road.