This content originally appeared on DEV Community and was authored by Artyom Titov
I'm not a great writer, and I'm certainly not great with putting my thoughts into words; this is my first post, so I'm going to keep this sweet and short.
React Native is a great framework for rapidly building mobile (and desktop too!) apps, but it has a reputation of being slow due to its JavaScript nature.
Let's be honest: a well-written React Native app can be indistinguishable from a well-written native app.
A lot of people expect performance issues to be rooted in React and native views integration, but in a majority of cases problems are actually only on the React side.
Backstory and a little explanation
I'm working on an app which contains a few dozen of views in it, and one reoccurring performance bottleneck has always been related to Redux store updates.
This isn't a very well noticeable performance issue on the web: your user switches the page and its components will be gone with it too.
On mobile, however, your app has to maintain a view hierarchy. When a new screen is pushed onto the nav stack, your previous screens with its components will be kept alive too.
These components are hidden down the stack hierarchy and are not visible to the end-user, but will still take up extra resources and be updated/re-rendered whenever, for example, Redux state changes (if the component has been subscribed to the Redux store via useSelector
and etc., obviously).
What do we do?
react-navigation
provides a hook called useIsFocused
, which allows your component to render different content based on the current focus state of the screen.
By using it, we can create our own useSelector
hook, which will only return fresh selector values when your screen is in focus:
import { useIsFocused } from '@react-navigation/core';
import { useSelector } from 'react-redux';
export function useAppSelector<Returned = unknown>(
selector: (state: RootState) => Returned,
allowUnfocusedUpdates = false,
) {
const isScreenFocused = useIsFocused();
const memoizedSelectedValue = useRef<Returned>();
return useSelector((state: RootState) => {
const selectedValue = selector(state);
if (allowUnfocusedUpdates) {
return selectedValue;
}
if (isScreenFocused) {
memoizedSelectedValue.current = selectedValue;
}
return memoizedSelectedValue.current!;
});
}
That's it! 🎉
There's no math, no statistics, I'm not going to surprise you all by making false claims like "woah get yourself a 500% performance improvement simply by adopting these 20 LoC in your project", but after implementing it myself I've gained a noticeable improvement in JS thread performance due to cutting off unnecessary re-renders of "heavy" and inactive screens.
Closing notes
Honestly, I'm very surprised that this problem isn't talked about as often as it should be. At least I didn't find myself any article about this particular case. I tried.
I don't think that my solution should be the way to go forward when working with Redux in a complex mobile app, but fortunately the folks over at Software Mansion are actually doing something even better to tackle this problem.
Thank you for your attention.
This content originally appeared on DEV Community and was authored by Artyom Titov
Artyom Titov | Sciencx (2021-11-28T00:00:42+00:00) Improving React Native app performance. Retrieved from https://www.scien.cx/2021/11/28/improving-react-native-app-performance/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.