Last active
March 9, 2023 17:12
-
-
Save arnoldc/5f4532f6aa010878c0af8d8f19749de8 to your computer and use it in GitHub Desktop.
[React Native] Optimizations Tips
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 1. Synchronization of input text when typing too fast | |
| /* | |
| One of the solutions for the synchronization problem is to remove the | |
| value prop from TextInput entirely. | |
| */ | |
| const PizzaTranslator = () => { | |
| const [value, setValue] = useState(""); | |
| const onChangeText = (text) => { | |
| setValue(text); | |
| }; | |
| return ( | |
| <View style={styles.container}> | |
| <TextInput | |
| accessibilityLabel="Text input field" | |
| placeholder="Type here to translate!" | |
| onChangeText={onChangeText} | |
| defaultValue={value} | |
| style={styles.textInput} | |
| // we remove the value prop here | |
| /> | |
| <Text style={styles.label}> | |
| {value | |
| .split(" ") | |
| .map((word) => word && "🍕") | |
| .join(" ")} | |
| </Text> | |
| </View> | |
| ); | |
| }; | |
| // 2. Always use a specialized component | |
| // example 1: Using ScrollView + View instead of Flatlist | |
| // note: FlatList uses ScrollView and View components | |
| // example 2: Using Flashlist | |
| // https://shopify.github.io/flash-list/ | |
| // 3. Choosing correct libraries | |
| // example 1: Use a bundle size of the app | |
| // https://github.com/IjzerenHein/react-native-bundle-visualizer | |
| // can get the details of any added library in the bundle; hence deciding if it’s worth keeping or removing that library. | |
| // Be more selective and use smaller specialized libraries. | |
| // example 2: Using momentjs instead of day.js | |
| // MomentJS 67.9 KB and DayJS 2.5 KB | |
| // example 3: import smaller libray | |
| // import { map } from 'lodash'; => instead of this | |
| // import map from 'lodash/map'; => use this | |
| // NOTE: use the import-cost in vscode extension to see realtime the size of the library | |
| // 3. Use libraries that is optimized for mobile platform not web! | |
| // example 1: Using react-native-webview instead of react-webview | |
| // example 2: Using react-native-svg instead of react-svg | |
| // example 3: Using '@react-native-firebase/database instead of '@firebase/database' | |
| // 4. Use Stylesheet API to pass styles | |
| /* | |
| The easiest way to style a component is to pass it an object with styles. | |
| While it works, you will not see it happening too much. It is generally | |
| considered an anti-pattern, unless you’re dealing with dynamic values, | |
| such as changing the style of the component based on the state. | |
| */ | |
| const App = () => { | |
| return ( | |
| <View style={styles.container}> | |
| <View style={styles.box} /> | |
| </View> | |
| ); | |
| }; | |
| const styles = StyleSheet.create({ | |
| container: { | |
| flex: 1, | |
| justifyContent: "center", | |
| alignItems: "center", | |
| }, | |
| box: { | |
| backgroundColor: "coral", | |
| width: 200, | |
| height: 200, | |
| }, | |
| }); | |
| // 5. Validate and check the types ahead of time when building a native module | |
| // example 1: | |
| import { NativeModules } from "react-native"; | |
| const { ToastExample } = NativeModules; | |
| export const show = (message, duration) => { | |
| ToastExample.show(message, duration); | |
| }; | |
| // to this | |
| import { NativeModules } from "react-native"; | |
| const { ToastExample } = NativeModules; | |
| export const show = (message, duration) => { | |
| if (typeof message !== "string" || message.length > 100) { | |
| throw new Error("Invalid Toast content"); | |
| } | |
| if (!Number.isInteger(duration) || duration > 20000) { | |
| throw new Error("Invalid Toast duration"); | |
| } | |
| ToastExample.show(message, duration); | |
| }; | |
| /* | |
| Why:every time there’s a rendering happening – just like you execute | |
| your native method with the JavaScript arguments. | |
| */ | |
| // 6. use the `useNativeDriver` for animations | |
| // example 1 | |
| const fadeAnim = useRef(new Animated.Value(0)).current; | |
| const fadeIn = () => { | |
| Animated.timing(fadeAnim, { | |
| toValue: 1, | |
| duration: 1000, | |
| useNativeDriver: true, // enables native driver | |
| }).start(); | |
| }; | |
| // [...] | |
| <Animated.View style={{ opacity: fadeAnim }} />; | |
| // 7. Use great library for animations | |
| // react-native-gesture-handler | |
| // reanimated-bottom-sheet | |
| // rive instead of lottie-react-native?? (debateable?) | |
| // https://twitter.com/guidorosso/status/1579607142382055425 | |
| // 8. Enable Hermes | |
| // example 1: Android | |
| /* | |
| project.ext.react = [ | |
| entryFile: "index.js", | |
| enableHermes: true | |
| ] | |
| */ | |
| // example 2: iOS | |
| /* | |
| use_react_native!( | |
| :path => config[:reactNativePath], | |
| # to enable hermes on iOS, change `false` to `true` and | |
| then install pods | |
| :hermes_enabled => true | |
| ) | |
| */ | |
| // 9 Use Proguard (Android) | |
| // Why: https://segment.com/blog/mobile-app-size-effect-on-downloads/ | |
| // example 1: | |
| // in android/app/build.gradle | |
| // def enableProguardInReleaseBuilds = true | |
| // 10. Test religiously | |
| // Testing Pyramid | |
| // 1. Web driver test (end-to-end) | |
| // 2. Unit test (jest, mocaha, chai, enzyme) | |
| // snapshot test | |
| // react-native-testing-library | |
| // 3. Static analysis (eslint, flow, typescript) | |
| // 11. Use a profiler | |
| // https://github.com/shopify/react-native-performance | |
| // https://github.com/callstack/reassure |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment