For the user location, we got another package built into expo which we can easily use and that's
location package.
Now just as before, you install it by following the instructions here and then you also see a usage example
down there,
so let's quickly do that.
Let's run expo install expo-location in our project and with that installed, we can now also add another
component, besides the image picker component,
I'll add the LocationPicker.js file because that's another thing I want to be able to do in this
app, I want to be able to pick a location. For that in the location picker component,
I'll import React from React of course because it will be a regular React component in the end and import
a couple of things from React Native and amongst these things is the view, a button which allows us to
start getting the user location, some text, also to show a default fallback text while no place has
been selected, an activity indicator to show a spinner whilst we're waiting for the location to be fetched
and maybe also alert to show an alert if something goes wrong and also the stylesheet of course to
style this component.
Now here, I have my location picker component which receives props and then we'll do something, set up
the styles object with Stylesheet.create and in the end, export the location picker component here
as the default, like that. Now for that component, how should its jsx code look like?
Ultimately, that's as always up to you but I will start very simple here and just have a view with a
button in there
which will allow me to start getting the user location and also another view in there which shows for
example my fallback text, no location chosen yet which will later be replaced for a little preview of
the place on a map,
so that's something I'll add later. Now here on the button, I'll therefore say get
user location for example, set the color to Colors.primary and for that as always make sure you
import that colors constant and up on pressing this, I unsurprisingly want to start fetching the
user location.
So here I'll add a new constant, get location handler, which is a function that will then use that location
API we just installed to get the user location and that's what I trigger when I click this button.
Now for the styling here, I'll add a style location picker, on this view here, I'll add another style map
preview, we could also style this text but I'll stick to the default and now add these two styles to
the stylesheet, so location picker here, there I'll add a margin to the bottom of let's say 15 and on
the map preview, there I'll also add a margin to the bottom of let's say 10 and the width of 100%
to take all the available width, a height of maybe 150
and also border color of this grayish color with the #ccc hex code and a border width of one,
it's a little bit like the image preview box. With that, we have this component set up,
we can now include it in the new place screen.
So in that screen component, I'll import location picker from components, location picker like this and add it
in the jsx code below the image picker, just like that.
If we now save that and we have a look, we see this box here.
Now when I click get user location, unsurprisingly the idea is that I start getting the user location.
For that, in our location picker component, we'll need to import some things here - we'll import everything
as location from the expo location package which we just installed. In addition for location, just as
for the camera, we'll have to ask for permissions, so we'll import everything as permissions from expo permissions,
that's also required. With that added here in the get location handler, I have first of all want to check
my permissions and for that, I can copy the approach I use in the image picker. There we have this verify
permissions function which we could of course therefore also outsource and write in a more generic way
to work in different components, here I'll just copy it, verify permissions. Of course here, I'm not asking
for the camera roll but for a location instead and you need to grant location permissions to use this
app and now verify permissions is executed here in the get location handler. We can use async await here
again to await the result of this check, so has permission is what I want to check here and if not, so
if we don't have permissions, well then I'll just return here,
there is no need to continue because we'll not be allowed to fetch the location anyways. Now otherwise
we can continue and now we can use the location package to get the current position async and this
does what the name implies, it gets the current user position. Now locating the user can take a while
which is why this is an asynchronous task and why this returns a promise, a promise which will resolve
once we got the user location or which will be rejected if it fails to fetch one. We can also configure
this with an object you pass to it, again as always in the official docs you learned all about all options
you can set there. For example one option you can set is the timeout and set this to five
seconds to make sure that if we couldn't fetch a location for five seconds, we stop trying
and we throw an error,
so the promise would then be rejected.
Now we can await this and of course wrap it into a try catch block, that's important to make sure we
do handle errors if we fail to fetch a location. Here I will then simply use the alert component which
I'm already importing to throw an alert, could not fetch location and then here, please try again later or pick
a location on the map, which is not possible right now but which we'll soon add and here a button where
we say OK. So that's an alert I show if fetching the location fails for some reason,
otherwise here
I expect to get back a location,
so that's the result of this promise in the end,
a location which we can use.
Now we can then utilize this location with the help of use state to manage some internal state here,
that's the picked location and set picked location and there, we can call use state which has no initial
value here
and then here in the location handler, we can set the picked location
to something, we'll have to see to what for now, to null but before we set anything here, let's
actually console log location to get a feeling for what's inside there.
Now I also want to show a spinner whilst we are fetching, so I'll manage another state in here and that's the
is fetching state and initially, that is of course false
but initially we're not fetching
but then here in the get location handler, before we start getting the location, I'll set is fetching
to true
and once we're done and that also includes if we got an error,
so thereafter I'll set it back to false and now we can use is fetching to show a spinner whilst we are
fetching.
So here if is fetching is true, I'll show the activity indicator and only otherwise, I'll show this text
and later we'll of course not just show the text but we'll also show a map snippet.
Now the activity indicator can be configured,
we can set the size to large and the color to Colors.primary if you want to. With all that,
let's go back and give it a try
here on iOS because whilst I can't add an image here, at least I can check the location and click on
get user location and now I'm asked whether I want to grant permissions which I do want to allow,
always allow and you see that spinner, it's super fast because it's a simulator, it also by the way
simulates the location, it's not the real location of your computer where you're running this on,
instead it's a default dummy location in San Francisco and here on Android, it's the same, if I click
get user location here, I need to grant permissions and once I did that, you see the spinner here and then
you see nothing but in the logs of course, you see something. There you see the objects which were
being logged where you have a coords sub object so to say so a field named coords and the object which
is another object with the accuracy and then a latitude longitude pair that describes this fake location,
both simulators use fake locations. You also got a timestamp.
So now we know what's in there,
so we can set the picked location, we can now set this to let's say an object where you store a latitude
of location.coords.latitude, that's what's in there, right and a longitude, .lng of
location.coords.longitude.
So now we have that picked location available and that picked location can now be used to for example
show a little map snippet here
once we do have a location. Before I do that just one tiny thing, I want to make sure that both the text
and the spinner here is centered, so on the map preview, I'll actually also set justify content to center
and align items to center, so that all the content in there is centered horizontally and vertically,
that's just a tiny thing,
so now you see that all in the center.
But with that, let's now make sure we show a little map snippet that shows the location the user picked.