I have a component in my app that uses an image as a background. The component is a chat screen where users can view previous messages and send new ones. The component is connected to redux store. The component looks like this at a high level
// Chat screen
<Image>
<Messages />
<TextInput />
</Image>
The chat screen component will be re-rendered every time user types anything. Sometimes, users have reported a lag in typing and seeing the typed character on screen. I am thinking if it is due to the fact that Image is also re-rendered every time user types something and if it would make sense to extract the Messages and TextInput into a separate component and connect that to the redux store such that the Image is not re-rendered when user is typing.
I don't want to make this change if it is not going to affect the performance and I don't have a sure shot way to measuring if that change has affected the performance as the lag is very intermittent.
Let me know if you think this would affect the performance of the component.
Using an image as a background can make performance issue, especially on Android. Use minified images as a background. Also, Try to capsulate the state change to the TextInput component by making a wrapper for it. It's a good idea to use FlatList for Messages component too.
Related
I have a sort of WhatsApp clone project. From the users listing component, it will redirect to each users chatWindow. I dont want to re-render the chatWindow component which was already rendered.
This is what happening
Navigate to ChatWindow1 from Userchannel - ChatWindow1 mounted
Navigate to Userchannel from ChatWindow1 - ChatWindow1 unmounted
Navigate to ChatWindow2 from Userchannel - ChatWindow2 mounted
Navigate to Userchannel from ChatWindow2 - ChatWindow2 unmounted
Navigate to ChatWindow1 from Userchannel - ChatWindow1 mounted again.
I know using state we can render the ChatWindow again. But Is there a possibility to avoid the unwanted re-renderng. Currently I am usinf RNRF as the router.
Optimising re-render can be done in multiple ways in react.
You can use PureComponent Implementation where react itself shallow compares the props and re-renders only when necessary.
If you want more granular control, go with shouldComponentUpdate which gives you a lifecycle method where you can compare the props and decide whether you want to avoid render. Please make sure the comparison is not complex. The more complex comparisons can make the app slow, in which case the optimisation back fires.
Use Flat list instead of List view or scrollview for better performance and make sure you add a keyExtractor and Item as a PureComponent.
Make sure the code splitting is properly done. you cannot optimise a very large amount code in a single page. If the components are small enough, you can optimise them better.
If you have a lot going on the JS, I would strongly recommend using a native navigation solution like react-native navigation
You can use console logs in render to find out the render count and take necessary actions. Please make sure that these optimisations can block necessary renders as well. So make sure props are different when you want to re-render things.
Regarding the mount / unmount
In most cases the navigation keeps the screens in the stack. Going back will not trigger a re-render. You can do one thing, make sure page works on props, so that re-render happens only when data changes.
Helpful Links:
https://medium.com/#ohansemmanuel/how-to-eliminate-react-performance-issues-a16a250c0f27
https://medium.com/vena-engineering/optimizing-react-rendering-61a10e741edb
Since your screens are unmounted there is nothing wrong to re-render when you navigate back to that screen. Of course you could avoid this by having all your screens mounted but that might cause memory leak.
This is a conceptional question, in this case a component is a screen, if that makes sense
Is there a good solution for fluently preloading a component? What I mean by that is perhaps calling a portion of a component, before opening up the view
an example of this is say, snapchat stories, when greyed out on press will simply load. The second press then opens up the view. Essentially allows you to preload before then navigation to the view
Is this a Redux task? Does anyone have an example?
Seems like some concepts are mangled in your mind. What you are trying to achieve is not to preload components, rather run logic before drawing anything on the screen OR preloading some media. Therefore, what you need to do is not to preload anything, but to seperate your logic from your view (let's say video data from showing video itself), retrieve / prepare data (download video for example) and after it is ready show your component.
Also, if what you are trying to preload is just media, you should checkout react-preload.
I built an alphabet scrubber that scrolls a SectionList. The SectionList is optimized through the use of getItemLayout. If I scrub over the alphabet, the scrolling happens as planned, but the SectionList does not rerender until I release my finger from the screen.
See this expo snack
Anyone ideas on how to solve this?
Solved it by going through the source code of PanResponder. PanResponder sets an interaction handle through the InteractionManager. You can access this handle through this.panResponder.getInteractionHandle() (undocumented feature), and then clear it everytime you scroll to a location in the SectionList:
if (this.panResponder.getInteractionHandle()) {
InteractionManager.clearInteractionHandle(
this.panResponder.getInteractionHandle()
);
}
This will move the SectionList up in the queue for doing its visibility calculations and renders.
I advice to heavily optimize this by clearing the interaction handle as few times as possible, since the InteractionManager is used for performance reasons.
For the sectionList to update dynamically you need to place the data its using into State. This Expo example(done by someone else), is a good example:
https://snack.expo.io/Syy1bqKxW
His panResponder has all its data in state and on every "handlePanResponderMove" he calls setState() to update the position every time it moves. All in all, if your data is not in state, it will not update dynamically for you. Placing your data into state in React-Native is how it keeps track of your data changes dynamically.
Hope this helps!
I'll do my best to explain this without code, which, in my opinion will not add clarity to this question as PanResponder code is quite complicated, and i need only concept, not the code itself.
So, i've implemented pagination, something like in this gif.
The idea is to have only 3 "pages" rendered at a time. If user goes to the next scene (swipes from right to left), app fetches one more scene from server and renders it behind currently active scene. etc.
Once user swiped to the next scene, i need to reset panResponder: the "nextScene" should appear at the default position between new nextScene and prevScene and then user will be able to swipe again.
The problem is that i don't know how to make it smooth. Right now i'm just passing new props (new currentScene, nextScene, prevScene) and changing key property of panResponder component. If a new scene contains images, they seems to be refetched each time when i'm changin key. That, probably, fixable by proper caching, but this makes me doubt if my approach is correct. Is there another way to make the reset of panResponder component and put the new scene into default position between new nextScene and prevScene.
I would like to know how to implement a component that has a fixed layout, but frequently updates its display.
Suppose it is an element that needs to be tied to some in app state like a stop watch timer:
(source: mzstatic.com)
If the timer is running then the hundredths of seconds should be ticking on every frame. But in react native my instinct is to make that a <Text>00:12.36</Text> element.
Obviously calling render() is wrong. Is creating a native module the only option for this? Or is there some mechanism to drive frequent display changes within pure js? Are there best practices in this case?
Checkout setNativeProps it allows directly set text (and other properties of elements). Here're docs
You will be able to set text of <Text> component as
this._textInput.setNativeProps({text: '00:12:36'});