50 React Native Tips — Part 2/2

Dino Trnka
Ministry of Programming — Technology
9 min readApr 22, 2019

So you’ve just finished Part 1 and are hungry for more? You’ve come to the right place! Without further ado, let’s continue our journey. 😎

  1. Folder structuring
    Folder structure in any project is very important for maintainability, and if you use redux you will really need to think about proper organization so you can easily access any module in your code later. There are two basic approaches to structuring folders in React Native. The first one is the function-first approach , where folders are named by the function of their files, for example containers, components, actions, reducers. Sounds simple, scales horribly, and including all the files required for a single screen is a mess. The second one is the feature-first approach, where each folder contains everything about a specific module in the app, so in this case you would have folders such as profile, login, feed, notifications and so on. This scales much better but doesn’t make a clear distinction between your UI and redux.
    The best solution is to always try to separate state management files from UI components. So, you can use the “Best of both worlds” approach, which is the Ducks file architecture. In this approach, all the UI files are isolated in views folder, whose inner architecture is function-first, and all state-related files are kept in redux folder, with a specific set of requirements. Since describing Ducks modular pattern in detail is outside the scope of this article, if you’re creating a new project look it up and see how you can implement it in your app.
  2. Use package.json to avoid relative paths
    I
    f you are a React Native developer, you probably have something like this somewhere in your code:
    import MyList from '../../../../../views/components/MyList'.
    It’s not cool, it’s tiresome and not easily maintainable.
    But there is a way to solve it! If you want to avoid typing all those ../../../'s and import directly from components folder, all you have to do is create a package.json file inside the components folder, with the following content: { "name": "components" }.
    Now that the folder is turned into a module, and you can import like this: import MyList from 'components/MyList'. However, be aware that doing this disables the autocomplete import feature in Visual Studio Code, so you might want to use it only in specific cases only, for example for importing static assets (images).
  3. Use debounce if you send API calls often
    If you are sending an API request for each keystroke (for example, fetching search suggestions while the user is typing something in the search bar), the number of requests can be overwhelming if the user types quickly. You can use lodash function _.debounce(onChangeText, 500) if you want to set a speed limit for sending requests.
  4. Implement loading indicators while waiting for API response
    This is something that is really easy to implement, but it will drastically improve the feel of your app and make it look more responsive and professional to the users.
  5. Implement empty placeholders when there is no data
    Empty placeholders, whether they are images or simple labels like “You don’t have any messages”, will make the app look neat even in cases where there is no data. First impressions are extremely important, and your new users will likely encounter cases where there is no data. Don’t let them stare into a blank screen.
  6. Get comfortable with the basics of native code on both platforms
    You don’t have to be a native iOS/Android developer in order to be a React Native developer, but you should at least know how to use iOS Pods, Info.plist and how to manually link libraries. The same goes for Android and its Gradle process and AndroidManifest configuration.
  7. Avoid heavy calculations in render()
    Your render() function needs to be as simple as possible, since it is the one that is called the most in the entire lifecycle. So keep it clean from all heavy calculations in order to increase your app performance. If you want to speed up a specific component, one of the first things you should do is count your renders and see if there are too many of them.
  8. Pure Components
    Since one of the biggest performance issues in React Native is too many unnecessary render() calls, you can extend PureComponent, whose purpose is to reduce the number of these calls. For example, a functional component will render every time its parent component renders, but a pure component will not, because it implements a lifecycle methodshouldComponentUpdate to check if a render is really required (it actually checks for changes in state or props). However, you need to be careful and understand how it works, because you might encounter false negatives if your component contains complex data structures whose changes won’t be detected.
  9. Clean up parameters you don’t use in components anymore
    If your component has gone through some heavy refactoring, chances are that some of the props it receives are not used anymore. Clean it up regularly to have a cleaner code and a better general idea of data flow in your application.
  10. Organize your constants
    If you have configuration variables that you use in many places of your app, such as navigation bar height, side menu width, page size for API calls, enums and so on, keep them all as named constants in a special file so you can always find and edit them easily.
    The same goes for colors. Instead of hardcoding HEX values all over the project, keep all your colors in one file so you can always keep track of every value. And yes, you should make constants even for black and white colors, because design requirements can be changed later (due to rebranding, project owner has been changed etc.), and you might need to change all black colors in your project to a different shade of black, or a different color altogether. Be sure to revise and clean this file up regularly so it doesn’t get cluttered with old, unused values. Naming your colors properly is also important. If your main app color is blue, don’t name the constant COLOR_BLUE because if it gets changed to red later, you will have to rename every single instance to COLOR_RED. Use COLOR_BASE instead.
    You should also keep all your message strings in one localization file so you can translate them easily when the need occurs. Even if you don’t need to translate your app in recent future, it’s still good to have a list with all the messages in one place.
  11. Constantly check how the app looks on different platforms and devices
    If you are constantly aware of how your app looks on different screen dimensions (bigger phones, smaller phones, tablets), you will save a lot of time and effort in the long run. In addition, even if you are developing for only one platform, keep in mind the other one. For example, using ActionSheetIOS won’t work on Android so you will have to either rewrite that code or create an Android-specific alternative later.
  12. Choose variable naming style and stick with it
    You like camelCase? Great. Or you are more of an underscore_case person? That’s also great. We will not go into which approach is better, because both have pros and cons. The important thing is to pick one and stick to it, and not mix them together. Be consistent.
  13. Increase touchable area with hitSlop
    If you have a small button which is hard to press, you could increase padding values to increase touchable area, but you can also use a property hitSlop to achieve the same purpose.
  14. Handle keyboard issues
    A keyboard is every mobile developer’s nemesis. Have you ever encountered an issue where you are presented with a list of clickable rows, but because your keyboard is open, you have to tap twice: the first time to close the keyboard and the second time for the row to react and open a screen? React Native’s <ScrollView> and<FlatList> both have a useful property called keyboardShouldPersistTaps. Setting its value to “always” will prevent this nasty behavior from happening.
    Another issue that often happens is the keyboard overlapping the text input fields you’re supposed to type in. Luckily, there are libraries out there such as react-native-keyboard-avoiding-scrollview, which prevent this inconvenience from happening.
  15. Always use both local and server validation
    Sure, there are some things only the server can validate, such as validation if the entered email exists in the database. But you should always implement as much client validation as possible, such as email format regex, minimum/maximum number of characters, and empty field validation.
  16. Use fitting data structures
    Don’t assume that every collection of data needs to be put into an array. Perhaps you’re better off with a key-value data structure like a hashmap. If your IDs are numbers, they need to be stored in a number data type like integer, even if the server returns them as strings in the response JSON.
  17. Avoid setting width and height for container components
    If your component’s child components already have set dimensions, double check if it’s really necessary to set dimensions for the container component as well. Sometimes it can be useful, but more often than not it’s better to let the container components resize themselves based on the dimensions of their children.
  18. Hardcode data in reducer if the API call isn’t ready
    If you are waiting for a specific API call to be implemented on backend, you can hardcode the agreed server response in your reducers. That way you won’t be blocked from developing a new feature and when the API call is ready, integration will be seamless.
  19. Be aware of your code complexity
    You should be at least partially aware of the computational complexity of your code. Sometimes a component spends more time computing data it received than it did on waiting for a server response. You can use Visual Studio extensions such as codemetrics to keep track of your code complexity in each method. This doesn’t mean you need to go through your entire codebase trying to optimize everything. After all, the performance of a released app on an actual device can differ greatly from the debug version on your simulator/emulator, so don’t fall into a trap of premature optimisation (“Premature optimization is the root of all evil” ~ Donald Knuth).
  20. Be aware of the difference between navigating and pushing screens
    No matter which navigation library you choose to use for your app, the rules are the same. Some actions require pushing a new screen to the application stack, while others require going to a screen you’ve loaded before. The push action adds a route on top of the stack and navigates forward to it. Navigate action will pop back to earlier in the stack if a component is already mounted there. Push will always add on top, so a component can be mounted multiple times. This is important for the back action and for the data you want to present. For example, do you want to allow opening one profile from another? You need the push action, because you’re essentially loading the same component twice, with different data, and you want to be able to return to the previous profile with the back button.
  21. Never, ever use Find/Replace functionality for refactoring
    It might seem like a faster solution if you need to quickly change a bunch of things on your project quickly, but there are way too many pitfalls you can (and trust me, you will) fall into. So just don’t even bother with it, and do things the old-fashioned way, or refactor using the refactoring tools provided by your IDE.
  22. Think about Human Interface Guidelines for Apple and Material Design Guidelines for Android
    Interface design details such as font size, text spacing, image resolutions, component organization and button dimensions might not sound all that important, but they make all the difference to your users. Even decisions such as whether the “OK” or “Cancel” button should be on the left or the right side of your screen are important. So be sure to research the do’s and don’ts for iOS and Android in order to provide a stellar UX for your users.
  23. Be very careful with Copy/Paste operations
    You might want to copy a component, function or some other piece of code and modify it. This is where a lot of unexpected errors happen because it can be very hard to notice a single property or value that you forgot to modify. So always be on your toes while doing any type of copy/paste.
  24. Transparency in color HEX codes
    Let’s say you are defining colors in your app with their hexadecimal rrggbb values. In this case, you would write pure black color as #000000, pure white as #FFFFFF and pure green as #00FF00. But what if you want to add transparency value to the color? Easy, just use rrggbbaa notation, where the last two digits represent the percentage of wanted color.
    So what would be the correct HEX value for black color with 50% opacity? The first thing that comes to mind is #00000050. But this is wrong! Since the values for opacity range from 0 to 255, the correct value for 50% would be 127, which corresponds to a hexadecimal value of 7F. Therefore, the correct answer in this case would be #0000007F. For a complete percentage to hex conversion table, check out this link.
  25. Lock dependencies
    If your package.json file has a dependency that looks like
    "some-cool-library": "^0.4.2", you might want to remove the ^ character in order to lock the dependency on that specific version. This will ensure that you don’t import breaking changes from the new versions of the library into your project.

That’s it! I hope you found this little guide useful.

Please let me know if you have other React Native or mobile development tips in the comments! 😃

--

--

Dino Trnka
Ministry of Programming — Technology

Programmer, gamer, musician and all-around geek. I get hyped easily and love to share it with others.