Build a Pokémon Radar App in React with Syncano

Daniel SiwekDaniel Siwek

Learn how to create a popular web application like Poké Radar in ReactJS. We will also use MobX as the state management library and Google Maps API.

Did you ever consider building your own Pokémon Radar? What if you could discover where the Pokémon in your neighborhood are, without having to roam aimlessly?

build-your-own-poke-radar Image Source

With a Pokémon Radar, everyone who uses your application marks where Pokémon are on the map. It is similar to Waze, where people help each other out by pinning locations of events; in this case, it’s for Pokémon. This way, everyone will gain from your Pokémon Radar, creating a wonderful community and huge database of all the seen Pokémon!

On the other hand, this application may cause jealousy inside your team, since it will help you get that much closer to becoming a Pokémon Master! (You know, like Ash's never-ending quest.)

I have great news for you: Thanks to the Syncano platform, creating the application is very simple.

Image Source

Our tutorial shows you how to create a popular web application like Pokémon Radar in ReactJS. In addition, we will use MobX as the state management library, and Material-UI with Google Maps API to render our application view. Syncano will store and manage the data. We're also going to use geolocation, which is supported by HTML5, to make sure you don’t miss any Pokémon in your neighborhood.

If you would like, you can preview your future application here: Syncano Hosting or Syncano Community GitHub Pages.

Step 1: Setting up Syncano

To start, we must create the data store structure on Syncano. We need two Classes to store our application data. Classes are schemas for Data Objects you will store in Syncano. This means they define a structure for the Data Objects to base their properties on.

Another cool feature of Classes is that you can see how many Data Objects are inherited from that specific Class.

You can create a new Class using our Dashboard interface or by API calls. In this step, we will show you how do that using your Syncano Dashboard.

Pokémons class on Syncano

Note: Be sure to click Add after creating each field!

Next, you will create a markers Class, which will hold the geolocations of the Pokémon.

markers class on Syncano

Step 2: Get the Pokémon repository

Step 3: Fill up the pokemons Class

In step 1, we created the two Classes we need, but now let's fill them up with data so our application can run! In the downloaded repository, you will find a file named pokeapi_to_syncano.js. This is a script that will fill your pokemons Class with real data from an external Pokémon API. In the next steps, we will be adding our Syncano API Key to this file.

var connection = Syncano({  
  apiKey: '<YOUR_API_KEY>',
  defaults: {
    instanceName: '<YOUR_INSTANCE_NAME>',
    className: 'pokemons'

Now, let's see how it works!

Creating application logic in the Application Store

All of our application magic is in the Store. From here, we are fetching data for our Syncano Classes, but what exactly is going on?

First of all, we must connect to our Syncano Instance where we defined our Classes.

const connection = Syncano({  
    apiKey: '<YOUR_API_KEY>',
    defaults: {
      instanceName: '<YOUR_INSTANCE_NAME>'

Next, we will use MobX as a state management library. Using this will allow our components to listen for changes in observable variables. Another awesome tool that MobX gives us is DevTools. Thanks to this, we can easily track the render time of our components, and see which ones are rendering right now. It’s a very nice tool for debugging our application.

In our store we will define two arrays for the data from Syncano, and some variables for each components lifecycle.

  @observable markers = [];
  @observable pokemons = [];
  @observable term = '';
  @observable centerMap = { lat: 0, lng: 0 };
  @observable zoomMap = 3;
  @observable popover = { show: false, position: {} };

Now, we will use a little trick in our fetching method. Typically, a list call using the Syncano API will only return 100 objects at a time, but we need all of the objects available! So, what we will do is run the all command on our DataObject method, which will get all of the data in pages. We then return each page using a callback and merge all the data into one object.

After that, we use a callback to define that all available pages have been returned and merged. This allows us to ascribe this object to Store. Our data from Syncano is now available to be used in react components.

  fetchPokemons = () => {'::fetchPokemons');
    const { DataObject } = connection;
    let objects = [];

    const all = DataObject.please({className: 'pokemons'}).all({}, {}, true, Infinity);

    all.on('page', function(page) {
      objects = [...objects,];

    all.on('stop', () => {
      this.pokemons = objects;
      this.fetchMarkers(); // this code fetches the markers Class

In the case of our markers Class, we must perform one extra step. Our markers Class doesn’t actually contain the pokemons Data Objects, but instead contains reference IDs to each object. So, what we need to do, is connect these two Classes in our code. To do that, we need to define a Pokémon object in each marker before we push it to the Store.

  fetchMarkers = () => {'::fetchMarkers');
    const { DataObject } = connection;
    let objects = [];

    const all = DataObject.please({className: 'markers'}).all({}, {}, true, Infinity);

    all.on('page', function(page) {
      objects = [...objects,];

    all.on('stop', () => {
      console.log('all::page', objects.length);
      const markers =, (marker) => { // This defines the pokemon marker
        return marker.geo && marker.pokemon_id && this.setMarkerObj(marker);
      this.markers = markers;

The Google Maps API also needs a specifically defined object, so we will do that in two other methods. The first method sets up marker objects and calls the second method which combines a marker with its linked Pokémon.

  setMarkerObj = (marker) => {
    return {
      position: {
        lat: marker.geo.latitude,
        lng: marker.geo.longitude
      defaultAnimation: 2,
      showInfo: false,
      pokemon: this.getPokemonInfo(marker.pokemon_id)

Here's the second method, which combines the marker and Pokémon:

  getPokemonInfo = (marker_pokemon_id = 1) => {'::getPokemonInfo');
    return _.find(this.pokemons, { pokemon_id: marker_pokemon_id });

Now, all we need to do is add new positions when you see Pokémon! All you need are coordinates and the ID of the Pokémon. After we add a new marker, we close the add screen and call the fetchMarkers() method to refresh our data.

  addMarker = (pokemon) => {
    const { DataObject } = connection;
    const newPokemon = {
      geo: {
        longitude: this.setPosition.lng()
      key: this.markers.length,

      .please({className: 'markers'})
      .then(() => { = false;


That's it for the Syncano part of this application! Check out our documentation to see what else you can do with our platform. Also, at the end of this post, we have included a couple of ways you could improve your Pokémon Radar.

Image Source

About the Google Maps API layer

In our project we are using the React-Google-Maps component.

The default map uses HTML5 geolocations, and shows us all available Pokémon markers in our area. When users are searching for and choosing one of the Pokémon, the map will re-render and display only the specified Pokémon. Also, we have replaced the default marker icon with the Pokémon image! :)

When a user clicks on a marker, he will see a popup with additional information about this Pokémon (name and type). Clicking the right mouse button on the map triggers AddPopover(), which allows a user to search and add new Pokémon to the map!

To simplify the displayed information on the map, we are using grid-based clustering. Grid-based clustering works by dividing the map into squares of a certain size (the size changes at each zoom) and then grouping the markers into each grid square.

Creating SearchBar component

The rest of the components are Material UI styles. We included the Autocomplete field, which makes it easier to add Pokémon. To do this, we retrieve our markers data from the Store and iterate over them. Our application also needs some style, so each marker in the Autocomplete field is defined as a MenuItem with the specific Pokémon image that was seen in the Avatar component.

When you click on a marker, Google Maps zooms in on that point, and shows you the area where that Pokémon was seen. This is possible because of the setCenterMap() method, which changes our observable value responsible for centering the map on a specific point.

See it in action!


Here is the code related to this functionality:

onTouchTap={() => appState.setCenterMap(marker.position)}  
setCenterMap = (position) => {  
  this.centerMap = position;
  this.zoomMap = 6;

Next, we are going to transform all typed text to lowercase for the sake of consistency. This is done thanks to the lodash library, and makes it possible to match the typed names to our data array. This narrows the possible results and makes the search more accurate.

filter={(searchText, key) => _.toLower(key).includes(_.toLower(searchText))}  

Creating AddPopover component

AddPopover() consists of Material UI components Popover and Autocomplete. Popover has two important properties: open, which is responsible for displaying the popover when a user clicks the right mouse button, and style, which is responsible for setting the correct position of the Popover.


style={{ marginTop: appState.popover.position.y, marginLeft: appState.popover.position.x }}  

Both of them are fetching from the Application Store. Inside the material-ui Popover, we will find the Autocomplete component, which is very similar to the SearchBar Autocomplete component. In this code below, we are iterate over the Pokémon array to retrieve our desired result.


    const { appState } = this.props;

    return, (pokemon, index) => ({
      id: pokemon.pokemon_id,
          secondaryText={, (type) => `${type} `)}
          style={{ lineHeight: '75px' }}
                backgroundImage: `url(${pokemon.image_url})`,
                backgroundPosition: 'center',
                backgroundSize: '50px 50px',
                width: '50px',
                height: '50px',
                borderRadius: '50%'

That's all! Thanks for reading! Below are some ideas for how you could improve this already great application.

Ideas to improve your Pokémon Radar App.

Here are some ideas to help improve this application! Feel free to submit ideas of your own in the comments below.

Real-time data with Channels

Connecting your application to a Real-time channel will allow you and your users to have fresh and current data without a page refresh. Thanks to this, no one misses any Pokémon!

Inform your users about new Pokémon with Schedules

Using Schedules, you can inform your users about new Pokémon in their area. With Schedules, you could send a daily email to all of your users, noting the newly available Pokémon in their area, using geolocations and a free email service.

Interact with your users by sending Push Notifications

Expand your application with a Push Notifications Socket. This will allow you to send messages and notifications to your users if a new Pokémon appears in their area, or if you have any updates to the map. This means you're connected with them anywhere!

Setup Triggers for new Pokémon

Syncano allows you to combine many of the available services, which results in infinite possibilities. You could set up a Trigger to run a Script that will, for example, send a message using a Push Notifications Socket whenever our data changes. This means that whenever someone adds a new marker on the map, users will be alerted via notifications on their personal devices.


As you can see, building a Pokémon Radar application is simple when using Syncano for your data. You can simply create and read Data Objects from Classes, and display them in your web app! But that isn't all that Syncano offers. Try to improve the application on your own, or with some of our ideas above, and let us know about it on Twitter by tweeting @Syncano.

Also feel free to ask any questions you have in the comments under this post, by joining our Slack community channel, or by writing to our support team at [email protected]. Good luck!

Image Source

Build powerful apps in half the time

Use our serverless platform to set up your backend in minutes.

Learn more
Daniel Siwek

Daniel Siwek