--
Chapter 2: Ola Begins
This is the second in a series of blog posts in which we outline our experience of building the Ola micro-app using React Native.
Read the first part of the blog here.
Now that we had decided on the tech stack and had setup the base project with the utils functions in place, it was time to get knee deep into Ola.
Navigation
The first hurdle we faced was to tackle transitions between screens. We were using React Navigation for navigating between screens, but when it comes to Ola, the map had to be the centerpiece for the entire screen. We did not want the map to go away or re-render while transitioning between screens, while the other components i.e. the headers and footers around the map, also needed to animate to give an immersive experience to the user.
The first thing that we did to tackle this was we built a map component sticking to our base principle of components being pure. All parameters that influenced the map were stored in the state, be it the markers that should be shown in the map, or the polyline points that would be used to show the path between two points and even the region that the user needs to navigate to. Everything was stored in state and could be dynamically modified via various actions so that there was no dependency on the component and the view layer could be controlled externally.
As we wanted to use the same screen, and just transition the components, we wrote our own version of the stack navigator. This stored the navigation states in store and instead of the entire screen getting updated, components of that screen like Footer, Header and Map got updated based on the route.
Now that we had a custom navigator to separate the logic between multiple screens while keeping the base map static, we were ready to tackle the next hurdle!
Map Zoom
When looking for a suitable mapping library for React Native, we chose the community driven react-native-maps library originally developed by AirBnB.. It seemed like a great option if you are using advanced map features such as callouts, markers and polygons. Also we needed those features in order to show content such as pickup markers and cab positions. It offered painless integration with Google Maps on both iOS and Android.
While developing with React Native maps was most times a joy, we did face a couple of subtle problems. The first arose when we launched an internal beta of the app. Suddenly, there was an influx of feedback about the maps being too sensitive. We also compared it to the Ola and Uber maps and quickly observed that when zooming in the maps, the maps in other apps did not scroll when zooming in to a certain position.
The Problem Statement: The maps seem to be extremely sensitive when choosing pickup and drop locations as upon zooming, the map scrolled as well and changed the selected pickup location.
When investigating the issue, we quickly found out that Google maps for iOS simply provided a property that offered the same thing, however there was no such alternative on Android and was excluded as such from React Native maps. It was an extremely important feature for us as it was detrimental to the user experience. Our first approach was to implement the solution in Javascript by disabling scrolling & zooming on the map, then capturing all the touches and sending it to the map manually. However, we soon realized that all the touches will have to be first detected by the native side, passed to Javascript which would then calculate the zoom/pan level and then passed back to the native side. As parallel animations ran whenever the map moved, and there was only one line of communication that was the bridge between Javascript and the native side. Also the performance would have been suboptimal even in the best of cases.
After some discussion, we decided to cut the middleman out. As it was only absent on the Android side, we decided to implement it directly on the native side of thing, leaving the Javascript side free to perform other tasks. We introduced a `disableScrollOnZoom` property on the React-native-maps map component. The property was already supported on the Google maps sdk on the iOS side and we wrote our custom logic for the Android side.
On the Android native side, we kept count of the number of fingers on the map. If the number of fingers was more than 1, we disabled all gestures on the map and started capturing the touches ourselves. From that, we figured out the zoom level and then manually setup the zoom level on the map.
Voila! Everything was right with the world again.
The final part of this blog will be up sometime next week. If there’s anything specific you’d like included in it, do us know in the comments.