React-Native update UI when value on element in array changes, without using ForceUpdate - user-interface

Imagine this: I have a FlatList presenting a list of message threads. Each cell has a label showing number of new messages in that thread. Each cell also shows a truncated string of the latest message in that thread. Other things are presented too. The list of threads is kept in redux and is set as the data prop for my FlatList. The class instances for the threads do not know of the FlatList and cannot force reload on it when something changes, eg a new message comes in (intentional design). The issue now is that the FlatList does not update when such an event occurs. It only updates when a new thread array is set (new instance).
How can I get the FlatList to update when any of the values in the threads changes?
A timed recurring reload is not preferred. I was thinking to have the threads update (by increasing) a value in redux called MessageThreadUpdateCount which would be a number. That would be done each time any UI connected value changes. The FlatList then uses that redux value as its ExtraData prop. Hence updating when that changes. Using a boolean instead of a number would be raise the question: what should set it to false, and when? Any other suggestions?

For the list to update you need to set the 'extraData' prop of the FlatList component,
This is a PureComponent which means that it will not re-render if props remain shallow- equal. Make sure that everything your renderItem function depends on is passed as a prop (e.g. extraData) that is not === after updates, otherwise your UI may not update on changes. This includes the data prop and parent component state.
exemple
<FlatList
data={this.props.data}
extraData={this.state}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
/>
With your state being change when you receive a new message. Note that you can replace 'this.state' by any variable updated when you get a new Message could be a counter for example.
(source: https://facebook.github.io/react-native/docs/flatlist.html)
Hope this will help you.

Related

CarouselView control: how to block user from getting to the next item in certain situations

I use the latest ver of .Net Maui. In the scenario there is ObservableCollection of items bound to ItemsSource's CarouselView. User is supposed to do some actions upon the current item to make it "valid" in order to be able to move to the next one. CarouselView should block user from swiping card to the next one until the current one is valid, and valid state is defined by properties of the item.
First thing that came my mind was to subscribe for one of Scroll or PositionChanged event and cancel the action propagation, but I do not think the events are cancelable, did not find it in the even arguments. Second less desirable way to implement is to add items dynamically to the ObservableCollection of items once current item got valid. It won't be able to go to the next just because the current is always the last. It though seems to be a bit of a hacky way to resolve this, and I would prefer to implement it on a view level rather than model level (adding items on the fly). So if you know more direct ways to get it implemented please let me know. Thanks.
Update: I'd like users to be able to swipe to all previously handled items (all valid), getting back and forward, but only for valid cards.
Set the property IsSwipeEnable to false when the current item is not yet valid.
From docs
IsSwipeEnabled, of type bool, which determines whether a swipe gesture will change the displayed item. The default value is true.

Display message (or empty graph) when empty dataset is added

I'm adding an onChange() handler to the crossfilter associated with my dc.js graph. One of the changes I'm looking for is the 'dataAdded' event. When I add a data set with >= 1 record, the graph renders properly and I see that onChange() callback gets triggered with the 'dataAdded' event. If I add a data set with 0 records then the graph does not render properly and the onChange() callback is never triggered. I would have thought that since I'm supplying an empty array to the crossfilter then it would trigger the 'dataAdded' event but evidently it does not. This makes some measure of sense, but still.
The main issue that I'm experiencing is that when the data set is empty then nothing is rendered. The graph doesn't render as it normally would (e.g., axis names, empty pie/donut/row/bar, etc) to give any indication that something happened.
What I was hoping to do was add a test as part of the 'dataAdded' event in order to see if the data set was empty. If it was then somehow let the user know that a request to the server was made but nothing came back. Is there a way to do this a different way? Is there a way where I can force the graph to render as empty? Make it so that the graph displays a custom message?
I've been digging around but haven't really been able to find out much information about this particular case.
thnx,
Christoph

React Native ListView optimization / performance on iPhone 5

I am working on a React Native application.
I have a Scene with a ListView with some Components inside.
Each one of the Components in the ListView can be marked as selected (or unmarked).
Once the Scene has focused in, I fetch the data and display those 500 Components.
I pass the props to each one of the Components in the OnRenderRow method.
Ideally, every time I click on one of the Components I would save the id inside a dictionary in the state and then I would trigger the fetch (now cached) again. Once I fetch the 500 Components again OnRenderRow checks if the ids exist in the dictionary and sets the isSelected prop to true (React will take care of rendering as selected).
Why I am fetching the data again?
In order to refresh React Native's ListView the datasource has to be 'marked as dirty'.
If I would try to refresh the list by reusing the same dataSource:
this.setState({dataSource: this.state.dataSource})
Since it's the same object it would not trigger any OnRenderRow. As far as I know the only way to force the update of the list is using:
ds.cloneWithRows(Array)
Which means it has to go through the whole 500 Components again (Actually it parses them all but it renders them in small windows of 20 or so)
This works pretty fast in the emulator but in the iphone5 it takes 2-3 seconds. I have the same problem with filtering.
Is there any way to force the ListView onRenderRow without parsing the whole dataSource again?
Note: The problem could also be related to Realm Native, but since the second time I fetch the elements I am caching the query and the problem persists its not probably the cause of it.

extjs Save component view state before removing it from parent component

Let me explain the my scenario. I am using ExtJS5. I have got a view component (let us name is viewOne) contain two combo boxes, button search and some action button, on click of search button the grid is populated. This viewOne is in a parent view component (viewParent). I need to load a second view (viewTwo) on selecting some grid row and clicking some action button a new view is loaded (viewTwo) in the parentView. When I come back from viewTwo to viewOne I need old values of combo boxes to re perform the search.
Currently I am storing the values of combo boxes in a store and set then when the after view render and call search. We have discarded card layout for this implementation.
I wanted to know how this can be done via Ext.state , I cannot find any example on the same that is close solution to my problem. Any other way of doing this ?
State seems reasonable for that. First of all you must set StateProvider (by calling Ext.state.Manager.setProvider) to instance of class which extends Ext.state.Provider.
Then state should work for you. Only thing that you must remember is to set stateful property to true and set stateId of the component.
Usually you don't need to save state by yourself. All built-in stateful components have defined state events. When such state event occur (eg. expand on panel) then state is saved automatically. You can customize state events by calling addStateEvents in initComponent.
To provide custom component state you should override applyState and getState methods. When you combine it with addStateEvents you have all what you need.
Example: http://jsfiddle.net/48jw81da/16/

Breaking event cycles in GUIs

When writing GUIs, I've frequently come over the following problem: Assume you have a model and a controller. The controller has a widget W that is used to show a property X of the model.
Because the model might be changed from outside the controller (there might be other controllers using the same model, undo operations etc), the controller listens to changes on the model. The controller also listens to events on the widget W and updates the property X accordingly.
Now, the following happens:
the value in W is changed
an event is generated, the handler in the controller is invoked
the controller sets the new value for X in the model
the model emits events because it has been changed
the controller receives a change event from the model
the controller gets the value of X and sets it in the widget
goto 1.
There are several possible solutions for that:
Modify the controller to set a flag when the model is updated, and not react to any events from the model if this flag is set.
Disconnect the controller temporarily (or tell the model not to send any events for some time)
Freeze any updates from the widget
In the past, I usually went for option 1., because it's the simplest thing. It has the drawback of cluttering your classes with flags, but the other methods have their drawbacks, too.
Just for the record, I've had this problem with several GUI toolkits, including GTK+, Qt and SWT, so I think it's pretty toolkit-agnostic.
Any best practices? Or is the architecture I use simply wrong?
#Shy: That's a solution for some cases, but you still get a round of superfluous events if X is changed from outside the controller (for instance, when using the command pattern for undo/redo), because then the value has changed, W is updated and fires an event. In order to prevent another (useless) update to the model, the event generated by the widget has to be swallowed.
In other cases, the model might be more complex and a simple check on what exactly has changed might not be feasible, e.g. a complex tree view.
The standard QT way of dealing with this and also the one suggested in their very useful tutorial is to make the change to the value in the controller only if the new value is different from the current value.
This is way signals have the semantics of valueChanged()
see this tutorial
Usually you should respond to input events in the widget and not to change events. This prevents this type of loop from occuring.
User changes input in the widget
Widget emits change event (scroll done / enter clicked / mouse leave, etc.)
Controller responds, translates to change in the model
Model emits event
Controller responds, changes value in widget
Value change event emitted, but not listened to by controller
Flags to indicate updaing work. You can wrap them in methods like BeginUpdate and EndUpdate.

Resources