When leveraging isomorphic rendering for a React component that displays time, I occasionally run into an issue where the server renders time at point A, but by the time the client picks up as a SPA, the time from point A has changed to point B, and React throws a React attempted to reuse markup in a container but the checksum was invalid warning:
The occurrence of the error is obviously more pronounced as you display more granular time units like seconds, but it would be nice to be sure I won't run into this on minute, hour, day, etc. boundaries as well.
Is there a way to tell React on the client side, effectively, "It's OK, this little portion of the DOM here can differ from the server side"? Or perhaps another way I haven't thought of?
More Detail
I'm using the React-Intl FormattedRelative component to display an item's creation date in a friendly fashion. The item's creation date of course stays the same between client and server (and gets passed to the client in a serialized Flux store), but the server render and client render time difference is just long enough that the rendered HTML frequently — but not always — differs.
This has been fixed with React Intl v2. It adds a initialNow property to stabilize the rendered times.
A new feature has been added to <FormattedRelative> instances in React Intl v2, they now "tick" and stay up to date. Since time moves forward, it was confusing to have a prop named now, so it has been renamed to initialNow. Any <FormattedRelative> instances that use now should update to prop name to initialNow:
Usage:
<FormattedRelative value={date} initialNow={Date.now()}/>
You can also provide this on IntlProvider in which case all FormattedRelative instances are stabilized.
Note: The <IntlProvider> component also has a initialNow prop which can be assigned a value to stabilize the "now" reference time for all <FormattedRelative> instances. This is useful for universal/isomorphic apps to proper React checksums between the server and client initial render.
Usage:
<IntlProvider initialNow={Date.now()}>
<FormattedRelative value={date}/>
</IntlProvider>
Reference: https://github.com/yahoo/react-intl/wiki/Upgrade-Guide#update-how-relative-times-are-formatted
Seeing as the data is going to change as soon as it renders client side, there is no point rendering that chunk server side.
So make a little component that renders this portion of information, but only by doing a force_update after mounting.
Before mount just put whatever you would like the user to see for the instant before rendering completes
Related
If my data is coming from a url (xml or json) and from that data I have to set the state of my react component. The thing is that data is chaning every 5 to 10 seconds. Its data of traffic passing from a certain location where police thinks that people do over speeding alot. so I have to use that source for setting my state in react and display the cars registration number if speed is more than 100km. So data, (speed, time, registration number) of the vehicals i am getting from url online and it changes. So I want it dynamic, means when it changes, it should be updated in state too.
so should I have to make a call of initializing (componentDidMount) for exmple 500ms or something like it, and how?
I havent tried anything yet, cuz I am confused how to do it.
I am pretty new to react and trying to use a web component in the template and there are is a thing i dont understand.
It can be seen in this example below if you run the page (may need to hit reload once). Then watch the console. You will see the log in the constructor() the outerHTML is not "ready" yet its missing all attributes in the markup and they arrive only later on (in the connectedCallback) which is the second log.
https://stackblitz.com/edit/react-ts-jcjuvs?file=App.tsx,index.tsx
Whats happening here? Is there anyway to force the attributes to be available initially? Or not taken off and then put back on?
Note that doing this in a normal page does not have the same effect.
https://stackblitz.com/edit/js-l4uh4f?file=index.js,index.html
a) whats happening?
b) can i make this not happen?
Thanks!
There no no guarantee that a web component will have access to attributes in the constructor and attribute values can change at anytime. You should use the attributeChangedCallback lifecycle callback to know when values are set.
The element's attributes and children must not be inspected, as in the non-upgrade case none will be present, and relying on upgrades makes the element less usable.
Requirements for custom element constructors and reactions
Webpack has an option that is called aggregateTimeout, this is explained as:
aggregate any other changes made during this time period into one rebuild
So the idea is, how can I bundle multiple changes within time period e.g. 1 second; to a single state update?
For example I have an editor in my react app, it updates the state each time the user types text on the editor, but I found that it makes the app a little laggy. So I want a timeout that ignores text inputs within, let's say 500ms, and it only updates after 500ms passed since the last time the user did text input.
How can I implement something like the case? Thanks.
I have an application which receives messages from a server every 1 second and via socket.io these messages are broadcast to a react component.
My react component is using a flux style architecture, so it calls an action when a message is received which adds (or updates) a record in a collection in a store.
My component monitors changes on the store and then updates the UI when it changes. In this case, it draws a marker on a map.
The problem is that due to the frequency of the updates my component redraws all markers every second, which I don't want.
I'm looking for an approach to allow my map component to respond to changes in a collection in a store, but not have the state update every second.
I thought I could have a collection for the raw data, and then only update the networkGPS collection selectively in my store, but the component seems to change based on any property in the store as they all seem to be part of its state.
In summary I'm looking to:
Collect data every 1 second in raw form and add this data to a store.
Bind a component to a collection in this store which I update only when changes require a UI redraw.
What I think I need to do:
Either:
Avoid putting the raw data into the state of the store (at the moment I'm unsure how to declare a collection which is not part of the state)
OR
Make my component more clever as to when it redraws, so it doesn't try to redraw on each state change.
I'm not sure which is the most appropriate solution for the problem, any info would be gratefully receieved.
Sorry if the question is a little unclear, I'm new to react / flux. Please do ask for any clarifications.
EDIT
At the moment I am getting round this issue by storing an array of the items (map markers in this example) I want my component to display in the component itself :(
When the state changes and render is called, I intercept the state properties, decide if anything needs to change in the collection of markers and only amend them if needed. If no changes are needed, the collection in the component stays the same and no redraw is performed.
This is not ideal, I feel like I should be able to allow my component to respond to only specific state changes but I've not found it yet, still looking for a better answer.
There are a couple of ways to approach this:
1) Use shouldComponentUpdate to compare old props and new props, re-rendering only the new marker states.
2) Switch to a cursor-based state tree that automatically triggers renders only for views that are bound to the specific parts of the state tree that have changed. I believe Baobab is one such library. See also Om (written in ClojureScript) and probably a number of other Flux implementations.
Given the impact of #2 my vote would be to go the route of #1.
I am not quite sure what's the problem that you face with updates every second.
However, the one place where you can queue the updates is between the socket.io and calling the action.
Instead of calling the action every second, you could queue the updates before sending it across to react.
Using https://github.com/reactjs/express-react-views as a starting point, I can successfully get server-side rendering/client-side mounting working. Problem I have is the size of the page once react has stamped data-reactid's over the state passed to renderComponentToString.
The object itself is a JSON payload from a server-side async call and comes in around 80KB. I pass this as is to renderComponentToString and the resultant page is over 20MB!
At this stage I'm thinking I could switch to renderComponentToStaticMarkup and take the hit client side for the first diff when I next update the state but wondering if there is a smarter solution here (props vs state?). Looking at the very clever react-quickstart (https://github.com/andreypopp/react-quickstart) I see the async state is effectively completely decoupled from the normal component lifecycle and therefore doesn't suffer from this issue however there's a lot of moving parts here and I'd rather come up with something more lightweight based on https://github.com/reactjs/express-react-views but with the necessary moving parts in place for client-side mounting to work.
Thoughts? Am I doing something wrong here?
I've resolved this for now:
The serialised payload for client-side mount was actually being rendered in the react render method, which was a noob error on my part. This was done rather than stringifying it and passing it down in a piece of non-react markup, which is what I should have done from the start.