---
title: "Developing Games with React, Redux, and SVG - Part 3"
description: "Learn how to make React and Redux control a bunch of SVG elements to create a game."
authors:
  - name: "Bruno Krebs"
    url: "https://auth0.com/blog/authors/bruno-krebs/"
date: "Feb 13, 2018"
category: "Developers,Tutorial,React"
tags: ["react", "redux", "svg", "game", "auth0", "animation", "state"]
url: "https://auth0.com/blog/developing-games-with-react-redux-and-svg-part-3/"
---

# Developing Games with React, Redux, and SVG - Part 3



**TL;DR:** In this series, you will learn how to make React and Redux control a bunch of SVG elements to create a game. The knowledge acquired throughout this series will also allow you to create other types of animations that are orchestrated by React and Redux, not only games. You can find the final code developed in this article in the following GitHub repository: [Aliens Go Home - Part 3](https://github.com/auth0-blog/aliens-go-home-part-3)

---

## Implementing the Leaderboard Feature in Your React Game

The first thing you will do to make your game look like a real game is to implement the leaderboard feature. This feature will enable players to sign in, so your game can track their max score and show their rank.

## Integrating React and Auth0

To make Auth0 manage the identity of your players, you have to have an Auth0 account. If you don't have one yet, you can <a href="https://auth0.com/signup" data-amp-replace="CLIENT_ID" data-amp-addparams="anonId=CLIENT_ID(cid-scope-cookie-fallback-name)">**sign up for a free Auth0 account** here</a>.

After creating your account, you just have to create an [Auth0 Application](https://auth0.com/docs/applications) to represent your game. To do this, head to [the Applications page on the Auth0 dashboard](https://manage.auth0.com/#/applications) and click on the *Create Application* button. The dashboard will show you a form where you will have to inform the *name* of your application and its *type*. You can type *Aliens, Go Home!* as the name and choose the *Single Page Web Application* type (your game is an SPA based on React after all). Then, you can click on *Create*.

![Creating the Auth0 Application to represent your React game.](https://images.ctfassets.net/23aumh6u8s0i/5pj3GTmuI8ExyWUAnd8if3/160bb83f92bafa4bf91371474ce071bc/creating-the-auth0-client-for-your-react-game)

When you click this button, the dashboard will redirect you to the *Quick Start* tab of your new application. As you will learn how to integrate React and Auth0 in this article, you won't need to use this tab. Instead, you will need to use the *Settings* tab, so head to it.

There are three things that you will need to do in this tab. The first one is to add the `http://localhost:3000` value to the field called *Allowed Callback URLs*. As the dashboard explains, *after the player authenticates, Auth0 will only call back one of the URLs in this field*. So, if you are going to publish your game on the web, be sure to add its public URL there as well (e.g. `http://aliens-go-home.digituz.com.br`).

After inputting all your URLs on this field, hit the *Save* button or press `ctrl` + `s` (if you are using a MacBook, you will need to press `command` + `s` instead).

The last two things you will need to do is to copy the values from the *Domain* and *Client ID* fields. However, before using these values, you will need to code a little.

For starters, you will need to issue the following command in the root directory of your game to install the `auth0-web` package:

```bash
npm i auth0-web@1.7.0
```

As you will see, this package facilitates the integration between Auth0 and SPAs.

The next step is to add a login button in your game, so your players can authenticate via Auth0. To do this, create a new file called `Login.jsx` inside the `./src/components` directory with the following code:

```js
import React from 'react';
import PropTypes from 'prop-types';

const Login = (props) => {
  const button = {
    x: -300, // half width
    y: -600, // minus means up (above 0)
    width: 600,
    height: 300,
    style: {
      fill: 'transparent',
      cursor: 'pointer',
    },
    onClick: props.authenticate,
  };

  const text = {
    textAnchor: 'middle', // center
    x: 0, // center relative to X axis
    y: -440, // 440 up
    style: {
      fontFamily: '"Joti One", cursive',
      fontSize: 45,
      fill: '#e3e3e3',
      cursor: 'pointer',
    },
    onClick: props.authenticate,
  };

  return (
    <g filter="url(#shadow)">
      <rect {...button} />
      <text {...text}>
        Login to participate!
      </text>
    </g>
  );
};

Login.propTypes = {
  authenticate: PropTypes.func.isRequired,
};

export default Login;
```

The component that you have just created is agnostic in terms of what it will do when clicked. You will define this action when adding it to the `Canvas` component. So, open the `Canvas.jsx` file and update it as follows:

```js
// ... other import statements
import Login from './Login';
import { signIn } from 'auth0-web';

const Canvas = (props) => {
  // ... const definitions
  return (
    <svg ...>
      // ... other elements

      { ! props.gameState.started &&
      <g>
        // ... StartGame and Title components
        <Login authenticate={signIn} />
      </g>
      }

      // ... flyingObjects.map
    </svg>
  );
};
// ... propTypes definition and export statement
```

As you can see, in this new version, you have imported the `Login` component and the `signIn` function of the `auth0-web` package. Then, you have added your new component to the block of code that is shown only if players have not started the game. Also, you have indicated that, when clicked, the login button must trigger the `signIn` function.

With these changes in place, the last thing you will have to do is to configure the `auth0-web` with your Auth0 Application properties. To do this, open the `App.js` file and update it as follows:

```js
// ... other import statements
import * as Auth0 from 'auth0-web';

Auth0.configure({
  domain: 'YOUR_AUTH0_DOMAIN',
  clientID: 'YOUR_AUTH0_CLIENT_ID',
  redirectUri: 'http://localhost:3000/',
  responseType: 'token id_token',
  scope: 'openid profile manage:points',
});

class App extends Component {
  // ... constructor definition

  componentDidMount() {
    const self = this;

    Auth0.handleAuthCallback();

    Auth0.subscribe((auth) => {
      console.log(auth);
    });

    // ... setInterval and onresize
  }

  // ... trackMouse and render functions
}

// ... propTypes definition and export statement
```

> **Note:** You have to replace `YOUR_AUTH0_DOMAIN` and `YOUR_AUTH0_CLIENT_ID` with the values copied from the *Domain* and *Client ID* fields of your Auth0 application. Besides that, when publishing your game to the web, you will have to replace the `redirectUri` value as well.

The enhancements in this file are quite simple. This list summarizes them:

1. `configure`: You used this function to configure the `auth0-web` package with your Auth0 application properties.
2. `handleAuthCallback`: You triggered this function in [the `componentDidMount` lifecycle hook](https://reactjs.org/docs/react-component.html#componentdidmount) to evaluate if the player is returning from Auth0 after authenticating. This function simply tries to fetch tokens from the URL and, if it succeeds, fetches the player profile and persists everything in the `localstorage`.
3. `subscribe`: You used this function to log if the player is authenticated or not (`true` for authenticated and `false` otherwise).

That's it, your game is already [using Auth0 as its identity management service](https://auth0.com/learn/cloud-identity-access-management/). If you run your app now (`npm start`) and head to it in your browser ([`http://localhost:3000`](http://localhost:3000)), you will see the login button. Clicking on it will redirect you to [the Auth0 login page](https://auth0.com/docs/hosted-pages/login) where you will be able to sign in.

After you finish the sign in process, Auth0 will redirect you to your game again where the `handleAuthCallback` function will fetch your tokens. Then, as you have told your app to `console.log` any changes on the authentication state, you will be able to see it logging `true` in your browser console.

![Showing the login button on your React and Redux game](https://images.ctfassets.net/23aumh6u8s0i/57jV86VbI5EHf8c0GYHB4X/16b629d88c601fab2f0bb799e7e0be6d/showing-the-login-button-in-your-react-game)

<include src="TweetQuote" quoteText="Securing games with Auth0 is simple and painless."/>

## Creating the Leaderboard React Component

Now that you have configured Auth0 as your identity management system, you will need to create the components that will show the leaderboard and the max score for the current player. For that, you will create two components: `Leaderboard` and `Rank`. You will need to split this feature into two components because, as you will see, it's not that simple to show player's data (like max score, name, position, and picture) in a nice way. It's not hard either, but you will have to type some good amount of code. So, adding everything into one component would make it look clumsy.

As your game does not have any players yet, the first thing you will need to do is to define some mock data to populate the leaderboard. The best place to do this is in the `Canvas` component. Also, since you are going to update your canvas, you can go ahead and replace the `Login` component with the `Leaderboard` (you will add `Login` inside the `Leaderboard` in a moment):

```js
// ... other import statements
// replace Login with the following line
import Leaderboard from './Leaderboard';

const Canvas = (props) => {
  // ... const definitions
  const leaderboard = [
    { id: 'd4', maxScore: 82, name: 'Ado Kukic', picture: 'https://twitter.com/KukicAdo/profile_image', },
    { id: 'a1', maxScore: 235, name: 'Bruno Krebs', picture: 'https://twitter.com/brunoskrebs/profile_image', },
    { id: 'c3', maxScore: 99, name: 'Diego Poza', picture: 'https://twitter.com/diegopoza/profile_image', },
    { id: 'b2', maxScore: 129, name: 'Jeana Tahnk', picture: 'https://twitter.com/jeanatahnk/profile_image', },
    { id: 'e5', maxScore: 34, name: 'Jenny Obrien', picture: 'https://twitter.com/jenny_obrien/profile_image', },
    { id: 'f6', maxScore: 153, name: 'Kim Maida', picture: 'https://twitter.com/KimMaida/profile_image', },
    { id: 'g7', maxScore: 55, name: 'Luke Oliff', picture: 'https://twitter.com/mroliff/profile_image', },
    { id: 'h8', maxScore: 146, name: 'Sebastian Peyrott', picture: 'https://twitter.com/speyrott/profile_image', },
  ];
  return (
    <svg ...>
      // ... other elements

      { ! props.gameState.started &&
      <g>
        // ... StartGame and Title
        <Leaderboard currentPlayer={leaderboard[6]} authenticate={signIn} leaderboard={leaderboard} />
      </g>
      }

      // ... flyingObjects.map
    </svg>
  );
};

// ... propTypes definition and export statement
```

In the new version of this file, you defined a constant called `leaderboard` that holds an array of fake players. These players have the following properties: `id`, `maxScore`, `name`, and `picture`. Then, inside the `svg` element, you added the `Leaderboard` component with the following parameters:

- `currentPlayer`: This defines who the current player is. For now, you are using one of the fake players defined before so you can see how everything works. The purpose of passing this parameter is to make your leaderboard highlight the current player.
- `authenticate`: This is the same parameter that you were adding to the `Login` component in the previous version.
- `leaderboard`: This is the array of fake players. Your leaderboard will use it to show the current ranking.

Now, you have to define the `Leaderboard` component. To do this, create a new file called `Leaderboard.jsx` in the `./src/components` directory and add the following code to it:

```js
import React from 'react';
import PropTypes from 'prop-types';
import Login from './Login';
import Rank from "./Rank";

const Leaderboard = (props) => {
  const style = {
    fill: 'transparent',
    stroke: 'black',
    strokeDasharray: '15',
  };

  const leaderboardTitle = {
    fontFamily: '"Joti One", cursive',
    fontSize: 50,
    fill: '#88da85',
    cursor: 'default',
  };

  let leaderboard = props.leaderboard || [];
  leaderboard = leaderboard.sort((prev, next) => {
    if (prev.maxScore === next.maxScore) {
      return prev.name <= next.name ? 1 : -1;
    }
    return prev.maxScore < next.maxScore ? 1 : -1;
  }).map((member, index) => ({
    ...member,
    rank: index + 1,
    currentPlayer: member.id === props.currentPlayer.id,
  })).filter((member, index) => {
    if (index < 3 || member.id === props.currentPlayer.id) return member;
    return null;
  });

  return (
    <g>
      <text filter="url(#shadow)" style={leaderboardTitle} x="-150" y="-630">Leaderboard</text>
      <rect style={style} x="-350" y="-600" width="700" height="330" />
      {
        props.currentPlayer && leaderboard.map((player, idx) => {
          const position = {
            x: -100,
            y: -530 + (70 * idx)
          };
          return <Rank key={player.id} player={player} position={position}/>
        })
      }
      {
        ! props.currentPlayer && <Login authenticate={props.authenticate} />
      }
    </g>
  );
};

Leaderboard.propTypes = {
  currentPlayer: PropTypes.shape({
    id: PropTypes.string.isRequired,
    maxScore: PropTypes.number.isRequired,
    name: PropTypes.string.isRequired,
    picture: PropTypes.string.isRequired,
  }),
  authenticate: PropTypes.func.isRequired,
  leaderboard: PropTypes.arrayOf(PropTypes.shape({
    id: PropTypes.string.isRequired,
    maxScore: PropTypes.number.isRequired,
    name: PropTypes.string.isRequired,
    picture: PropTypes.string.isRequired,
    ranking: PropTypes.number,
  })),
};

Leaderboard.defaultProps = {
  currentPlayer: null,
  leaderboard: null,
};

export default Leaderboard;
```

Don't be scared! The code of this component is quite simple:

1. You are defining the `leaderboardTitle` constant to set how the leaderboard title will look like.
2. You are defining the `dashedRectangle` constant to style a `rect` element that will work as the container of the leaderboard.
3. You are calling the `sort` function of the `props.leaderboard` variable to order the ranking. After that, your leaderboard will have the highest max score on the top and the lowest max score on the bottom. Also, if there is a tie between two players, you are ordering them based on their names.
4. You are calling the `map` function on the result of the previous step (the `sort` function) to complement players with their `rank` and with a flag called `currentPlayer`. You will use this flag to highlight the row where the current player appears.
5. You are using the `filter` function on the result of the previous step (the `map` function) to remove everyone who is not among the top three players. Actually, you are letting the current player stay on the final array if they don't belong to this select group.
6. Lastly, you are simply iterating over the filtered array to show `Rank` elements if there is a player logged in (`props.currentPlayer && leaderboard.map`) or showing the `Login` button otherwise.

Then, the last thing you will need to do is to create the `Rank` React component. To do this, create a new file called `Rank.jsx` beside the `Leaderboard.jsx` file with the following code:

```js
import React from 'react';
import PropTypes from 'prop-types';

const Rank = (props) => {
  const { x, y } = props.position;

  const rectId = 'rect' + props.player.rank;
  const clipId = 'clip' + props.player.rank;

  const pictureStyle = {
    height: 60,
    width: 60,
  };

  const textStyle = {
    fontFamily: '"Joti One", cursive',
    fontSize: 35,
    fill: '#e3e3e3',
    cursor: 'default',
  };

  if (props.player.currentPlayer) textStyle.fill = '#e9ea64';

  const pictureProperties = {
    style: pictureStyle,
    x: x - 140,
    y: y - 40,
    href: props.player.picture,
    clipPath: `url(#${clipId})`,
  };

  const frameProperties = {
    width: 55,
    height: 55,
    rx: 30,
    x: pictureProperties.x,
    y: pictureProperties.y,
  };

  return (
    <g>
      <defs>
        <rect id={rectId} {...frameProperties} />
        <clipPath id={clipId}>
          <use xlinkHref={'#' + rectId} />
        </clipPath>
      </defs>
      <use xlinkHref={'#' + rectId} strokeWidth="2" stroke="black" />
      <text filter="url(#shadow)" style={textStyle} x={x - 200} y={y}>{props.player.rank}º</text>
      <image {...pictureProperties} />
      <text filter="url(#shadow)" style={textStyle} x={x - 60} y={y}>{props.player.name}</text>
      <text filter="url(#shadow)" style={textStyle} x={x + 350} y={y}>{props.player.maxScore}</text>
    </g>
  );
};

Rank.propTypes = {
  player: PropTypes.shape({
    id: PropTypes.string.isRequired,
    maxScore: PropTypes.number.isRequired,
    name: PropTypes.string.isRequired,
    picture: PropTypes.string.isRequired,
    rank: PropTypes.number.isRequired,
    currentPlayer: PropTypes.bool.isRequired,
  }).isRequired,
  position: PropTypes.shape({
    x: PropTypes.number.isRequired,
    y: PropTypes.number.isRequired
  }).isRequired,
};

export default Rank;
```

Nothing to be scared of about this code either. The only unordinary thing that you are adding to this component is [the `clipPath` element](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/clipPath) and a `rect` inside the `defs` element to create a rounded portrait.

With these new files in place, you can head to your app ([`http://localhost:3000/`](http://localhost:3000/)) to see your new leaderboard feature.

![Showing the leaderboard in your React Game](https://images.ctfassets.net/23aumh6u8s0i/7zDgzmih6wVEW0uuJfBP17/177147d358e6db1b41eb1ff9a6c29f2b/showing-the-leaderboard-in-your-react-game)
