Reactjs: Change state in render only some times - javascript

It is my understanding that you are not supposed to change states in the render function cause that would cause and infinite re render or the component.
This makes perfect sense, but I find myself in a particular situation. I am building an offline application and I am using an offline storage system to retrieve data. Now, whenever a method is called to get certain data, cache is checked, if it is not expired the component will be able to access the data and therefore nothing happens, but if it is expired there is a call to the API, the data is updated and the interested components re-rendered.
These methods will change the state of the component the first time they are called because they are going to the API grabbing the new data and re-rendering, and then they will not change the state anymore because the data will already be in cache.
Now, I could call these methods in component will mount, and that is what I am doing now, but if I am forced to re call them, I need to unmount and remount the components. Is this the only possible way of doing this?
Thanks!

Well the first step is understanding that state management and rendering needs to be decoupled which you got already.
Now what you can do is consider your external state/cache element as an observable object (ie. I want to do something like observableObject.listen('change', onChangeHandler); you can use EventsEmitter from the events library). You do that listening on componentDidMount and clean up in componentWillUnmout. That onChangeHandler is very simple: this.setState({ value: observableObject.value }) which will trigger a component re-render which should be a pure function that outputs DOM nodes depending on props being passed and it's own state.
This means that your logic of checking if the cache is invalid is not on a per request of the value (inside rendering) but rather think of the object as self contained. It regularly checks if itself needs to notify its listeners that it changed. Since JS does not do parallel execution you don't have to deal with threads and synchronization. You know that at the point in time your render function executes it will have the latest value. If after rendering the logic that checks for cache executes and it sees that it needs to be updated it simply notifies as said earlier its listeners and that makes your component re-render because your onChangeHandler changed the state.
Hope I helped.

Related

What is the use case for each vue.js life cycle hooks?

So I know somethings about vue's life cycle hooks but for some of them I can't think of any real world use case or example that should be done in them and I think it might help me to better understand them by finding out their use case.
here is what I know and don't know about them:
Creation Hooks
beforeCreate(): events and lifecycle have been initialized but data has not been made reactive --- use case ??
created(): you have access to data and events that are reactive but templates and virtual DOM have not yet been mounted or rendered --- use case: API calls
Mounting Hooks
beforeMount(): runs before the initial render --- use case ??
mounted(): you have access to the reactive component, templates and rendered DOM --- use case: modifying the DOM
Updating Hooks
beforeUpdate(): runs after data changes and before the DOM is re-rendered --- use case ??
updated(): runs after data changes and the DOM is re-rendered --- use case ??
Destruction Hooks
beforeDestroy(): runs before tear down --- use case: clean ups to avoid memory leak
destroyed(): runs after tear down --- use case ??
Thanks in advance to anyone helping me to understand these concepts better ;)
According to official VueJS website:
Each Vue instance goes through a series of initialization steps when it’s created - for example, it needs to set up data observation, compile the template, mount the instance to the DOM, and update the DOM when data changes. Along the way, it also runs functions called lifecycle hooks, giving users the opportunity to add their own code at specific stages.
Having that in mind, we have:
beforeCreate
The beforeCreate hook runs at the very initialization of your component. data has not been made reactive, and events have not been set up yet.
Usage
Using the beforeCreate hook is useful when you need some sort of logic/API call that does not need to be assigned to data. Because if we were to assign something to data now, it would be lost once the state was initialized.
created
You are able to access reactive data and events that are active with the created hook. Templates and Virtual DOM have not yet been mounted or rendered.
Usage
Using the created method is useful when dealing with reading/writing the reactive data. For example, if you want to make an API call and then store that value, this is the place to do it.
The above are famously called as creation hooks, as opposed to mounting hooks.
Mounting hooks are often the most used hooks. They allow you to access your component immediately before and after the first render. They do not, however, run during server-side rendering.
beforeMount
The beforeMount hook runs right before the initial render happens and after the template or render functions have been compiled.
Usage
This is the last step you should perform your API calls before it’s unnecessary late in the process because it’s right after created — they have access to the same component variables.
mounted
In the mounted hook, you will have full access to the reactive component, templates, and rendered DOM (via this.$el).
Usage
Use mounted for modifying the DOM—particularly when integrating non-Vue libraries.
There also some hooks, which are called updating hooks.
Updating hooks are called whenever a reactive property used by your component changes or something else causes it to re-render. They allow you to hook into the watch-compute-render cycle for your component.
Use updating hooks if you need to know when your component re-renders, perhaps for debugging or profiling.
There are:
beforeUpdate
The beforeUpdate hook runs after data changes on your component and the update cycle begins, right before the DOM is patched and re-rendered.
Usage
Use beforeUpdate if you need to get the new state of any reactive data on your component before it actually gets rendered.
updated
The updated hook runs after data changes on your component and the DOM re-renders.
Usage
Use updated if you need to access the DOM after a property change
And last but not least, there are destruction hooks.
Destruction hooks allow you to perform actions when your component is destroyed, such as cleanup or analytics sending. They fire when your component is being torn down and removed from the DOM.
There are:
destroyed
By the time you reach the destroyed hook, there’s practically nothing left on your component. Everything that was attached to it has been destroyed.
Usage
Use destroyed if you need do any last-minute cleanup or inform a remote server that the component was destroyed
beforeDestroy
beforeDestroy is fired right before teardown. Your component will still be fully present and functional.
Usage
Use beforeDestroy if you need to clean-up events or reactive subscriptions.
This is the stage where you can do resource management, delete variables and clean up the component.
Keep in mind that these are the main lifecycle hooks and there are some other minor ones such as activated and deactivated that you can look into.
Here is a link that might help you further down the line.

Three questions about Store in Flux

Following the flux concepts we can get the next assertions for which I couldn't find explanations.
Every store will receive every action.
Why? My suggestion: since a store contents some business-logic we have to provide it with all possible changes and data so the store can decide what to do with them on its own.
The data in a store must only be mutated by responding to an action.
Why? My suggestion: the reason is violation of unidirectional data-flow in case of not responding to an action.
Every time a store's data changes it must emit a "change" event.
Why? I can't get this point.
Flux is just a way of managing the data flow of your application, so it is up to the developer to make sure this actually happens. But I'll try to paint a picture of why these concepts are a part of Flux.
Every store will receive every action.
If you have only one dispatcher in your application, every store will listen to actions dispatched through that dispatcher. It is up to you whether or not the store should act on the action dispatched, but to be able to react on it the store has to know of it.
Not all actions should lead to changes in a store, though. But the dispatcher simply doesn't care, because it won't know anything about the store implementation. It's just telling all stores that this action happened, do what you want with it or go on with your life without caring.
The data in a store must only be mutated by responding to an action.
You're right that doing it with a different approach could be violation of unidirectional data-flow. Doing things this way makes sure all parts of your application has the correct state based on the actions that happens.
By not doing it this way you would let go of one of the flux strengths. Update your store based on dispatched actions, and other stores will also be aware that the action happened, and thereby react to it if they want to. If you update the store directly you will end up having no clear picture of what parts of your application that are altering the state of your store.
Every time a store's data changes it must emit a "change" event.
People often describe the stores in a flux application as the source of truth. When a store's data changes, the basis for the visualization of your data changes. You want to be confident that if my store holds a certain value, this is what my application uses as it's data.
It's related to the first quote here. The store doesn't know if a listener depends on it's data. By emitting a change, it will let all listeners know that hey, I changed. Make sure you have all my latest changes. If you don't emit change, the listener could end up displaying something based on old data.
All of these statements are related to the same thing: If an action happens in your application, don't make any assumptions about which part of your application that wants to know the details of it. Make sure everyone can act on it, if they want to.

Are there any cases when React updates DOM automatically

All articles I've read on React show the code when I should explicitly call this.setState() to trigger DOM update. This seems to be manual triggering of change detection. I call this.setState, React re-renders Virtual DOM and then compares it with the native DOM for changes - if anything changed, the DOM is updated. Here is the quote from the docs:
4) Every second the browser calls the tick() method. Inside it, the
Clock component schedules a UI update by calling setState() with an
object containing the current time. Thanks to the setState() call,
React knows the state has changed, and calls render() method again
to learn what should be on the screen.
Compare it with Angular digest cycle which automatically checks for binding changes and updates DOM. Although I have a way to trigger manual changed detection for a component, it's usually not needed.
My question is whether there are any cases when React triggers DOM update without requiring me to call this.setState() manually, i.e. automatic virtual DOM update?
React is a state machine that maintains a virtual representation of the DOM in memory, which automatically updates/renders (where appropriate) when this state changes.
The reason you see setState being called to trigger a rerender is because this is the most common (only?) means of updating the data structure that feeds this internal DOM representation (which will in turn feed down through the properties of children).
It's not that setState is a manual call to rerender, it's that setState causes the state to change, which in turn causes React to run a diff and update where appropriate. It's all about cascading the data to reflect the current state of your application. If that state hasn't changed then there's nothing to update, and therefore no need to rerender.
This is also why it's a very bad idea to mutate the DOM out from under React, as this more often than not results in a loss of parity between React's virtual representation of the DOM and the actual DOM.
Try not to think about React data bindings in terms of Angular bindings, rather think about it in terms of emulating what Angular bindings do within the context of step-by-step state changes.

Partial state changes for Vaadin's AbstractJavascriptComponent

I'm implementing a JavaScript-based Vaadin component that will need to show and update a relatively large data set. I'm doing this by extending AbstractJavaScriptComponent.
I'm trying to keep the JS side as "dumb" as possible, delegating user interactions to the server using RPC, and which updates the shared state. Then the JS connector wrapper's onStateChange function is called with the new state, which causes the DOM to be updated accordingly.
I have 2 problems:
I don't want to transfer the whole data set each time a small part gets updated.
I don't want to entirely rebuild the UI each time either.
I can solve the second problem by keeping the previous state and comparing parts of it to find out what changed and only make the necessary DOM changes.
But that still leaves the first problem.
Do I have to stop using Vaadin's shared state mechanism and instead only use RPC for communicating the changes to the state?
Update:
I've been doing some testing, and it certainly appears that Vaadin's shared state mechanism is horrible in terms of efficiency:
Whenever the component calls getState() in order to update some property in the state object (or even without updating anything), the whole state object is transferred. The only way to avoid this, as far as I can see, is to not use the shared state mechanism and instead use RPC calls to communicate specific state changes to client.
There are some issues with the RPC approach that will need to be resolved, for example: if you change a value multiple times within a single request/response cycle, you don't want to make the RPC call multiple times. Instead, you want only the last value to be sent just like the shared state mechanism only sends the final state in the response. You can keep dirty flags for each part of the state that you want to send separately (or just keep a copy of the previous state and compare), but then you need to somehow trigger the RPC call at the end of the request handling. How can this be done?
Any ideas on this are welcome!
Update 2:
Vaadin 8 fixes the root issue: it sends only the changed state properties. Also, it doesn't call onStateChange() on the JS connector anymore when only doing an RPC call (and not changing any state).
OP is correct in stating that shared state synchronisation is inefficient for AbstractJavaScriptComponent-based components. The entire state object is serialised and made available to the Javascript connector's onStateChange method whenever the connector is marked as dirty. Other non-javascript components handle state updates more intelligently by only sending changes. The exact place in the code where this happens is line 97 in com.vaadin.server.LegacyCommunicationManager.java
boolean supportsDiffState = !JavaScriptConnectorState.class
.isAssignableFrom(stateType);
I'm not sure why state update is handled differently for AbstractJavaScriptComponent-based components. Maybe it's to simplify the javascript connector and remove the need to assemble a complete state object from deltas. It would be great if this could be addressed in a future version.
As you suggest, you could dispense with JavaScriptComponentState completely and rely on server->client RPC for updates. Keep dirty flags in you server-side component or compare old state and new state by any mechanism you want.
To coalesce the changes and send only one RPC call for each change, you could override beforeClientResponse(boolean initial) in your server-side component. This is called just before sending a response to the client and is your chance to add a set of RPC calls to update the client-side component.
Alternatively, you could override encodeState where you have free-reign to send exactly whatever JSON you like to the client. You could choose to add a list of changes to the base JSON object returned by super.encodeSate. Your javascript connector could interpret as appropriate in its onStateChange method.
Edited to add: calling getState() in your server-side component will mark the connector as dirty. If you want to get state without marking it as dirty then use getState(false) instead.
Following our discussion about this, I've created a drop-in replacement for AbstractJavaScriptComponent that transmits state deltas and includes some extra enhancements. It's in the very early stages but should be useful.
https://github.com/emuanalytics/vaadin-enhancedjavascript
The solution is deceptively simple: basically re-enabling state difference calculation by bypassing this line of code in com.vaadin.server.LegacyCommunicationManager.java:
boolean supportsDiffState = !JavaScriptConnectorState.class
.isAssignableFrom(stateType);
The implementation of the solution is complicated by the fact that the Vaadin classes are not easily extended so I've had to copy and re-implement 6 classes.
Vaadin's shared state works exactly like you want out of the box: when a component is added to the DOM first time, the whole shared state is transferred from server to client, so that it's possible to display the component. After that, only changes are transferred. For example, one changes the caption of a visible component by calling component.setCaption("new caption"), Vaadin only transfers that new caption text to client and "merges" that to the client-side shared state instance of the component.

Why should addChangeListener be in componentDidMount instead of componentWillMount?

I saw this line as an answer to another question on here:
"componentWillMount should be componentDidMount, or else you'll leak event emitters in node."
and I don't really understand it. Can someone explain with more detail?
More info:
Building a react application with flux, as part of the initial render, a child component computes some data. Ideally, after this data is computed, I would like to call an action that updates the store's state with a portion of this new data.
Normally, updating the store's state emits a change event that causes a re-render. However, because the change listener isn't being added until componentDidMount (rather than in componentWillMount), my top level component isn't able to listen for the change that occurs during the initial render and initiate a re-render.
If I move the addChangeListener to componentWillMount that would seem to fix this issue, but the above quote suggests that this is a bad idea?
I think the prevailing wisdom that listeners should be set in componentDidMount because it prevents problems in isomorphic applications is a mistake. I think in 98% of cases for non-isomorphic applications setting listeners in either componentWillMount and componentDidMount will work the same way, but it is conceptually wrong and in the 2% of cases (such as the example given in the original question) it will do the wrong thing.
There are git issue discussions and comments in the React source code suggesting that it would be preferred that componentWillMount wasn't called on the server at all, but if it isn't then problems are created in the checksum test comparing the server prerender to the client initial render. Having componentWillMount on the server means that it isn't executed as part of the component lifecycle in this case, but this is being used as an excuse to not count it as part of the lifecycle in any case.
In fact, componentWillMount is exactly the right place to register listeners if you are not creating an isomorphic application. If you are creating an isomorphic application then you have to make some compromises due to the checksum/lifecycle issue not being ideal in this case (maybe just testing for the server environment and then not registering listeners?).
In non-isomorphic applications adding listeners in componentWillMount can save unnecessary re-renders in some cases and will register them in document order. The advantage of document order is that if you have a way to flush pending events as components are re-rendered (for example, takeRecords on a MutationObserver) then you can ensure the document is re-rendered top down instead of bottom up, converting the rendering complexity to linear from polynomial.
Additionally, there is no danger period between the initial render and when the listener is registered where the Store can change without triggering a render, causing the view to be out of sync with the Store (the example problem given in the original question). If the listener is registered in componentDidMount you either need to make sure the Store isn't changed in componentDidMount calls in children, or else force a re-render/re-sync after registering the listener, which if done in componentDidMount is done in reverse document order which may be polynomial complexity (depending on how/if the React setStates are aggregated).
Is hard to understand what that quote means without more context. What I can tell you is that there are huge differences between the two of those methods.
On one hand, componentWillMount is called before the component is actually added to the DOM. This is the last chance you have to update component's state and get it rendered before the component is rendered by the browser.
On the other hand, componentDidMount is called once the component has been attached to the DOM (the real one).
What you need really depends on your use case. In general, componentDidMount is used to integrate with other libraries (like jQuery), it provides a way to modify the HTML rendered by the component.
I suggest you to read these links:
https://facebook.github.io/react/docs/component-specs.html#mounting-componentwillmount
https://facebook.github.io/react/docs/component-specs.html#mounting-componentdidmount
https://facebook.github.io/react/tips/use-react-with-other-libraries.html

Categories