When building mobile applications performance is really crucial. If we compare React for web development with React-Native, the latter is much more restrictive in the sense that performance mistakes are sometimes far more reaching, even taking into account the golden quote of Donald Knuth “premature optimization is the root of all evil”. This talk is going to provide a deeper dive into principles and practices of making sure your app behaves as fast as possible. We will look at the common mistakes of component design, which lead to performance degradation. How to make lists more performant and animations more fluid. I will also introduce some of the tools, which might help you discover bottlenecks in your application.
7. Morale => Rethinking React-Native
• Mobile users have high standards in terms of app responsiveness and
animations
• Not thinking about performance is almost certainly would result in
slow app
• Rarely users write about performance directly
• Lots of performance cases can be solved on the React-Native level
8. Who am I
• Bob Ilya Ivanov
• React-Native 3 years
• React.js 5 years
• Software Development 8 years
20. Why – summary
• Performance is already slow for small sample 100 artists (500ms)
• Performance degrades with more data
• Slow responsiveness stack because of JS single threaded
21. Where
• 1 to * relationships in our hierarchy
• <FlatList or {items.map(item => …} where the count is unknown or varied
• No control over the number of items in our hierarchy
• No control the density of state updates
23. Update Complexity (big O for onPress)
• Current – O(n * m)
• n – number of artists
• m – number of boxes
• Goal – O(1)
Page
Artist 1
StatusBar
Box 1 Box 2... Box M
Artist 2 …
StatusBar2
Artist N
StatusBarN
24. Where – summary
• Look for FlatList or .map in your codebase
• Look for content of variable length
27. PureComponent
Used for classes. Shallow compare === for all properties of props, state
and context
React.memo
Used for function. Shallow compare === for all properties of props and
context
42. • Popularity is based on the most popular artist in the current list
• Artist A 3 000 000 – 1
• Artist B 20 000 – 0.00666666667
• Artist C 1 020 0 00 – 0.34
• Artist D 3 000 001 – 1
popularity = artist.listeners / maxListeners;
3 000 00020 000
0, 0.00000001, 0.00000002, … 1
43. • Popularity is based on the most popular artist in the current list
• Artist A 3 000 000 – 1 needs update to 0.999999667
• Artist B 20 000 – 0.00666666667 needs update to 0.00666666444
• Artist C. 1 020 0 00 – 0.34 needs update to 0.339999887
• Artist D 3 000 001 – 1
popularity = artist.listeners / maxListeners;
3 000 00020 000
0, 0.00000001, 0.00000002, … 1
44. • Popularity is based on the most popular artist in the current list
• Artist A 3 000 000 – 100
• Artist B 20 000 – 0
• Artist C 1 020 0 00 – 34
• Artist D 3 000 001 – 100
popularity = Math.round(artist.listeners / maxListeners * 100);
20 000 3 000 000
0, 1, 2, 3, … 100
45. • Popularity is based on the most popular artist in the current list
• Artist A 3 000 000 – 100 – no need to update
• Artist B 20 000 – 0 – no need to update
• Artist C 1 020 0 00 – 34 – no need to update
• Artist D 3 000 001 – 100
popularity = Math.round(artist.listeners / maxListeners * 100);
20 000 3 000 000
0, 1, 2, 3, … 100
47. Rendering summary
• Measure on real devices
• Indentify places where performance degrages
• Make sure you are using pessimistic scenarious (lots of data on slow
device)
• Indetify where you are calling redundant renders within FlatLists or
.map. You can use console.log, why-did-you-update, profilers, etc..
• Refactor the API and usage of your components to make sure no new
instances are being created during FlatList renders
49. Slow Code
• Internal long-running code (do not assume, measure)
• External long-running code
_.sortBy(artists, [a => a.getListeners()]);
for (let i = 0; i < 10000000; i++) {
//...
import {preinitializedOperation} from 'heavy-library';
50. I need a [min,max] from a set of random numbers
longRunningOperation() {
for (let i = 0; i < 10000000; i++) {
//...
this.setState({
minValue,
maxValue,
isRunning: false
});
render() {
return (
this.state.isRunning ?
<LoadingIndicator />