/ beacons

Create a dating app with React Native and Matchmore

We have already covered how to use Matchmore in Swift iOS, it's now time for the new kid on the block: React Native. After this tutorial you will have a good understanding in how to create your own dating app with Matchmore!

Requirements

  • If you haven’t installed React Native on your computer, you can find some information on how to it here.
  • This tutorial requires some basics in React Native.
  • We will use Yarn in the following guidelines.
  • You need a Matchmore account. Register here for free.

Quick and easy way to start with Matchmore: React Native

Let's start off with creating a React-Native app.

  1. Open your terminal, and type the following command:
react-native init DatingApp
cd DatingApp
react-native run-ios --simulator
  1. It creates a React Native project.
  2. You should now see the normal welcome screen. (Of course, this should not be new to you!)

welcome

Now let's add Matchmore into the mix!

Install the Matchmore SDK

In order to install Matchore to your React Native project, you have to open your terminal, locate your project and enter the next command.

yarn add "@matchmore/matchmore"

Yarn will install Matchmore in your project.

Get the API key

To use Matchmore, you have to get the API key. After logging in (register for free here) do the following:

  1. Create a new app.
  2. Obtain the API key and store it somewhere for later usage (in section Set up Manager).

alt text

Setup persistence

You need to wire in the persistence, you can use something which works with your existing applications, or browsers localStorage. Here we will use AsyncStorage from React Native.

const { AsyncStorage } = require("react-native");

const save = async (key, value) => {
  await AsyncStorage.setItem(key, value);
};

const load = async key => {
  return await AsyncStorage.getItem(key);
};

const remove = async key => {
  return await AsyncStorage.removeItem(key);
};

module.exports = {
  save,
  load,
  remove
};

Save this file as a storage.js. You can find these snippets here.

This will later be used while wiring the manager.

Setup the manager

For simplicity, we will do everything in the App.js file, so lets setup Matchmore!

In your App.js add these imports:

import { Manager, LocalStoragePersistenceManager } from "@matchmore/matchmore";
import "./storage";

Put your API key somewhere handy, as for example:

const apiKey = "YOUR_API_KEY";

Now on the start of the application we should initialize the manager and wire in the persistence.

In our App component let's do:

async componentDidMount() {
    PlatformConfig.storage = Storage;
    const localPersistenceManager = new LocalStoragePersistenceManager();
    await localPersistenceManager.load();
    this.manager = new Manager(
      apiKey, undefined, localPersistenceManager
    );
  }

And we need to setup our device as the main device. The first created device is our main device.

let myDevice = await this.manager.createMobileDevice(
    "me", //your device name, specific for the application
    "ios", //platform
    "DEVICE_TOKEN"); //token to route matches, like apns, fcm, websockets

Make it work!

Great - we're now up and running! Now, we would like to know who is nearby. In order to do that, let's create a subscription.

let datingSubscription = await this.manager.createSubscription(
      "Dating App", //topic specific to your applications, you can have multiple topic per app, it is up to you how will you model it, we will provide some insights about this soon
      10000, //range of subscriptions in meters, lets start of with 10km
      86400, //duration of how long the subscription will last, in seconds, lets put in 24 hours
      "age >= 18" // matching selector
    );

The matching selector is a selector which will filter out only publications which you are interested in. Think of it as SQL for publications you will receive! Here, we're saying that we're looking only for publications with a property age greater or equal than the property.

Cool! We're now waiting for THE one!

But we are missing one thing... We have to be detectable by others too. We need to Publish ourself! Let's create a Publication!

let datingPublication = await this.manager.createPublication(
      "Dating App",
      10000, //m
      86400, //s
      {age: 29, name: "Lucas"} //publication properties
);

As we mentioned before, publication properties are the data we want to be searched by, our interests, picture url, age... whatever makes sense for your app.

Ok, let's be real - we are just starting, nobody is out there. We need to create some mocking people to test our and develop against.

We can create virtual pins, which here will mimic other people looking for their second half.

async makePerson(name, properties) {
    let pin = await this.manager.createPinDevice(`pin-${name}`, this.state.coords);
    let publication = await this.manager.createPublication(
      "Dating App",
      10000, //m
      86400, //s
      properties,
      pin.id //last argument is explicit device id to which we with to attach the publication or subscription
    );
}

Pins are usually static, and they need a location. But let's cheat a little and supply our own location.

Let's add a placeholder for our state.

  constructor(props) {
    super(props);
    this.state = {
      coords: {},
    };
  }

We will also provide a callback for location updates. So when the callback is fired we can create pins and their publications.

this.manager.onLocationUpdate = async location => {
  this.setState({ coords: location.coords });
  await this.makePerson("clara", { name: "Clara", age: 18 });
  await this.makePerson("sam", { name: "Sam", age: 24 });
  await this.makePerson("alex", { name: "Alex", age: 23 });
  await this.makePerson("clover", { name: "Clover", age: 27 });
};

Now we have "people" around. We can wait for matches!

But first, what are matches?

Bluntly speaking its publication + subscription + match id.

Matchmore is notifying your device in real-time every time a match occurs. Basically, you can implement an action based on the received matches.

The next code will show you how to get the matches:

this.manager.startMonitoringMatches();
this.manager.onMatch = match => {
  this.setState(previousState => {
    return { matches: [...previousState.matches, match] };
  });
};

Now we are rolling! Every time we get a match we will fire the closure which will update our component state.

So when you get a match, it will then have a publication field, and it will have properties.

What are properties again?

{ "name": "Clover", "age": 27 }

What can we do with this knowledge? Show it to the user!

Lets modify the render function.

render() {
    return (
      <View style={styles.container}>
        {this.state.matches.map(match => (
          <Text key={match.id}>Matched with {match.publication.properties.name}!</Text>
        ))}
      </View>
    );
  }

When we run the app, we will see:

matches

So this means that:

  • We get our own publication
  • We get some of them multiple times

This is because we check publications and subscriptions multiple times, on every location update. It is up to the developer to filter out redundant matches, as sometimes it might be beneficial for your app to react to them.

Let's reduce the duplications. First let's remove ourselves.

We will refactor the publication code to look like the following:

let pub = this.manager.publications.find(
   pub => pub.properties.name == "Lucas"
);
if (!pub) {
  this.datingPublication = await this.manager.createPublication(
    "Dating App",
    10000, //m
    86400, //s
    { age: 29, name: "Lucas" } //publication properties
  );
} else {
  this.datingPublication = pub;
}

if (this.manager.subscriptions.length == 0) {
  this.datingSubscription = await this.manager.createSubscription(
    "Dating App",
    10000, //m
    86400, //s
    "age >= 18" // matching selector
  );
} else {
  this.datingSubscription = this.manager.subscriptions[0];
}

The manager instance has publications, subscription and devices properties, which let's access locally cached entities.

Thanks to the locally cached entities, you can now filter out the received matches.

Now we can use the datingPublication to filter out the received matches.

Next step is reduce our duplicate potential dates.

Let's filter out only the ones tied to our publication.

this.manager.onMatch = match => {
  if (
    match.publication.id == this.datingPublication.id &&
    match.subscription.id == this.datingSubscription.id
  )
    return;
  if (match.subscription.id != this.datingSubscription.id) return;
  let alreadyExists = this.state.matches.filter(
    m => m.publication.id == match.publication.id
  );
  if (alreadyExists.length > 0) return;

  this.setState(previousState => {
    return { matches: [...previousState.matches, match] };
  });
};

Now we got only the matches which are relevant for out application.

Lets make it nice

Let's add pictures to our dates we will use awesome Pexels.

We put the image url into properties of a publications. These are for querying but also for putting some data for your app to work with.

{
  "name": "Clover",
  "age": 27,
  "img":
    "https://images.pexels.com/photos/247322/pexels-photo-247322.jpeg?auto=compress&cs=tinysrgb&h=426&w=645"
}

And let's use some React Native components:

 render() {
    return (
      <View style={styles.container}>
        <FlatList
          data={this.state.matches.map(m => {
            m.key = m.id;
            return m;
          })}
          renderItem={({ item }) => (
            <View style={styles.item}>
              <Image
                style={styles.image}
                source={{ uri: item.publication.properties.img }}
              />
              <Text style={styles.label}>{item.publication.properties.name}</Text>
            </View>
          )}
        />
      </View>
    );
  }
//...
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#F5FCFF"
  },
  label: {
    fontSize: 20,
    textAlign: "center",
    margin: 10
  },
  item: {
    flexDirection: "row",
    flex: 1,
    padding: 10,
    height: 144
  },

  image: { width: 144, height: 144 }
});

And we will get a nice looking list which is live updated with our local potential dates.

list

Really easy! You can go and review the code of the app we made here.

Happy coding!

Create a dating app with React Native and Matchmore
Share this

Subscribe to Matchmore Blog