Links very slow to display 'large' components - reactjs

I am working on a React app, and within it there is a page with a lot of graphs and large list component, which takes some time to load (performance dependant). This is fine for now, but the issue comes from the following:
at the first render, there is an API call (App wide as different pages use the same data). A loading spinner shows while the API data is fetched
Once the data is fetched, it is Redux manages the state, and each component just takes what it needs from there (no more loading).
My issue is that when I navigate between pages trough links (react-router), after I click on the link it takes a while for the page to show and the menu to update the current page. None of the state data has changed in that timeframe, so I assumed a PureComponent would prevent re-render, but it doesn't work.
Is there any way to not re-render the page? I would expect to click on a link an immediately see the page that was already loaded before.
Sorry if the question is obvious, I got quite confused while researching this, with cold splitting, lazy loading, etc. which seems to be more about initial load vs. navigation?

If you have a large component dataset to mount and your state does not changes or affects re-renders you could prevent component from unmounting entirely.
If you are using react-router you can rely on setRouteLeaveHook.
If your unmount depends on conditional rendering, it is easier as you can hide your component in various way, including css display:none

There are several ways you can do this
The first one would be to not unmount the component, just hide it with CSS and display: none, but that's a shit solution if you ask me, since you'll still have the component in the DOM.
Another solution that you can use is the one that the guys from the Facebook team used when creating the official website for React. Once you hover over the link to the page, send a request to prefetch the data for that page. So, before the user even clicked, you will have the request already sent.
Another solution you can use is to cache the data. If you are not worried about users with older browsers waiting a bit for the component to load again. You can keep the data for the component in localStorage, then, when you are about to mount the component, check if the data is already in localStorage if it's there, just render the component, if not, just grab the data again.
A combination of the first and the second option would make your component pretty much always instantly render.

Related

Presentation component is getting cached while moving between screens

I am building a react-native app, in which all screens share the same generic functionality like
1. Making ajax requests
2. convert snake_case keys to camelCase
3. show loading indicator while fetching data
4. subscribe to redux store and expose store as props
here are the tools I am using
react-native
expo
redux
react-redux
react-navigation
My container has no idea what urls to fetch because it is used with all the components. I am calling the container component in this way
const fetchUrls = store => return [url, url];
return MycontainerComponent(WrapperComponent)(fetchUrls);
this seems to work fine on initial load, but didn't work when visiting a screen, navigate to another and come back to the first screen again. Its as if components are cached and not recomputed again. this is for me as long as no data in the store changed. so I wrote a watcher inside the container component and to see if any value in the store changes, the component will re-render. but then this worked fine until I had one more problem.
I want to support user switch like in gmail because mine is a parent app and a parent can have 2 or more children studying at the same school and u can understand the rest.
Now when I am switching the user, I updated the redux store and I thought it would re-render stuff and it would be all fine. Until I hit with reality.
When I switch user, it seems as if the component is trying to unmount and fetch urls for new store values at the same time and react complaints with typical "don't setstate in the componentwillunmount, its a no-op, unsubscribe etc."
I have no idea what's happening, can anyone shed some light on this. Thanks.
With a stack Navigator the screens are not unmounted after they lose focus. This is a performance optimization. If you want to execute logic when a screen regains focus put your logic in NavigationEvents onWillFocus or onDidFocus.

How to cache or prevent re-render of large reagent component

I have a reagent single page application. At the root component, I have a route dispatcher that renders component according to route. Something like:
(defn page []
[(get component-lookup #current-page-name)])
I have a list page and a detail page, where user frequently switches back and forth.
Problem is, switching between these two pages destroys and re-create an entire page worth of components. This slows down page transition noticeably, especially in mobile devices. In contrast, switching from one detail page to another is very fast, as react figured only a few components need to be re-rendered.
My first attempt at optimization is to have both pages rendered all the time, but add display:none whenever they are not visible. This speeds up page transition, but changes the meaning of lifecycle methods. For example, component-did-mount would execute, but the component is not visible and I cannot update its scroll position.
Would there be a better way to do this? Maybe it is possible to unmount a component tree, save it along with its subcomponents and states/virtual dom, to be remounted later with new props?
I don't think you're going to be able to do this without forking react. The lifecycles are inherently tied to modifications to the virtual dom--that's their whole point of existence.
It's a little surprising that the mere rendering of the DOM elements are too slow, unless your page has thousands of dom elements or lots of media. What are you doing during mount? If it is compute intensive, I'd look there to see if you can separate out that logic and cache it so that it is a lightweight process to switch components.

React.js component rendering the same images from Instagram repeatedly if current route is refreshed

I need help with figuring out how not to make my react.js component rerender same images from Instagram and add them to the exisitng in the view.
I have a react-instafeed container in my react.js component, which is fetching 20 latest images from my Instagram account and renders them in a neat grid. The react-instafeed element is a wrapper around the popular instafeed.js framework and makes the same methods and configurations available in react.js environment.
On initial load it fetches the images and renders them. However, if the current route is refreshed (by pressing the button in the header navigation, for example), it fetches all 20 images once again and adds them in the view, and so on.
I tried dealing with it by setting something like 'loaded' in the state in the 'success, or 'after' methods of the instafeed, but that's clearly not working and is anti-pattern.
I tried doing it with componentDidMount, with the result of a doubled http call on initial rendering and 20x2 images at once.
Apparently, setting state is not the right strategy in this case. How could I either prevent the element from making a n-th call to Instagram, or maybe destroying the element on componentWillUpdate()?

Refresh "Button" that only refreshes components if their props have changed

I'm pretty new to React and Redux and I've been setting my environment in the past week.
I was wondering if their was such a thing as a refresh button that doesn't refresh the whole page but just the components containing the props that have changed in the store.
Example :
User_1 changes the store.
User_2 clicks a refresh button on his page (container).
The components containing props that have been modified are refreshed for User_2.
The perfect situation would be if User_2's interface components would refresh as soon as User_2 does the action, but I don't think it's possible yet. (If it is, please mention it)
Thanks in advance
UPDATE:
If you use GraphQl, it's worth looking into their "subscription" solution.
If your two user's are on different computers, then the store is not shared between them. Changes made to one user's store are not going to impact the store of a second user.
It sounds like what you really want is websockets. But this would be something you need to manage with the server-side of your application first, and which react/redux would merely consume.
In general, components will always instantly update when their props change. If a component didn't update, then it's props are still the same.

How to check when the react components get rendered or rerendered

Is there any way to get logs of which all React components get rendered or rerendered when any event/action is performed. I just want to check whether any unwanted React component is getting rerendered. I know we could achieve this by adding consoles in render function, componentWillReceiveProps or componentWillUpdate. But I have number of components in my webapp. Adding console statements in each component would be a mess. Is there a better way?
A nice option is to visualise React components in the chrome timeline. This lets you see which components exactly get mounted, updated, and unmounted and how much time they take relative to each other. That feature was added as part of the release of React 15.4.0. You can take a look at the official blogpost to get a better insight, but summing up, those are the steps to get it up and running:
Load your app with ?react_perf in the query string (for example, http://localhost:3000/?react_perf).
Open the Chrome DevTools Timeline tab and press Record.
Perform the actions you want to profile. Don't record more than 20 seconds or Chrome might hang.
Stop recording.
React events will be grouped under the User Timing label.
After that, you will get a cool visual representation of mounting, updating and unmounting of your different components over time
In addition to rauliyohmc answer. Profiling tool he described is really helpful and powerful, but if your task is just checking if there are unnecessary re-renders (i.e. ones which did not lead to DOM changes) you can use nice and simple react-addons-perf tool. It has printWasted method which will provide you info about wasted re-renders.

Resources