How To Create a Music Player in Reason With The useContext Hook Part 1
Tags: reason, react, learning, tutorial
Published: 2019-10-20 11:47:42

---
title: How To Create a Music Player in Reason With The useContext Hook Part 1
published: true
tags: reasonml, react, learning, tutorial
series: How To Create a Music Player in Reason
canonical_url: https://www.rockyourcode.com/how-to-create-a-music-player-in-reason-with-the-use-context-hook-part-1
---

**UPDATE**:  
ReasonML + BuckleScript is now [Rescript](https://rescript-lang.org/blog/bucklescript-is-rebranding).  
As the ecosystem has changed around those tools, this blog post is not accurate anymore.

---

# What Are We Building?

This tutorial will show you how to build a **music player with [ReasonReact][reasonreact] and the `useContext` hook**.  
You will learn how to bootstrap a ReasonReact project, how to build a simple application, and how to use hooks with ReasonReact.

**[☞ View Demo][demo]**

**Why ReasonML and ReasonReact?**  
[ReasonReact][reasonreact] offers a type-safe way to build React applications. It leverages the mature OCaml language that comes with a superb type system. It also offers a blazingly fast compiler and excellent JavaScript-oriented tooling.

_Disclaimer_: I'm a ReasonReact beginner myself, and I can't promise you that the tutorial will follow best practices.  
The blog post series is a port from the excellent **[How to Use the useContext Hook in React][upmostly]** article by James King.

The tutorial assumes a basic familiarity with React. ReasonReact is React under the hood.

You can find all the code on _[GitHub][repo]_.

## What is `useContext`?

From the _[React docs](https://reactjs.org/docs/context.html)_:

> Context is designed to share data that can be considered “global” for a tree of React components, such as the current authenticated user, theme, or preferred language.

We will build a custom `MusicPlayer` component and a `useMusicPlayer` hook that will allow our app to gain access to a simple mp3 [HTML Audio player](https://developer.mozilla.org/en-US/docs/Web/API/HTMLAudioElement).

## Bootstrapping The Project

ReasonML is a syntax and toolchain for Ocaml, and we will need to install some npm packages to use it. You will need **Node.js** and **npm** (or yarn).

### Installation

Install [Bucklescript and Reason](https://reasonml.github.io/docs/en/installation):

```bash
npm install -g bs-platform --unsafe-perm
```

(I use [pnpm](https://pnpm.js.org/) for installing local packages, that's why you'll find a `pnpm-lock.yml` file in the [repository][repo].)

We need BuckleScript to compile ReasonML to JavaScript.

For **editor support**, check the [Reason Docs](https://reasonml.github.io/docs/en/editor-plugins).  
For Vim, you can check my blog post about [ReasonML Development With Vim](https://www.rockyourcode.com/reason-ml-development-with-vim).

### Creating The ReasonReact Project

In your terminal:

```bash
bsb -init reason-music-player -theme react-hooks
cd reason-music-player && npm install
```

The commands create a boilerplate project which we'll have to configure to our needs.

> **Please note:**  
> The boilerplate has since changed. I'll help you set up your project with [webpack][webpack]. That isn't strictly necessary anymore with the new configuration.  
> If you don't want to use webpack, you can use the new default boilerplate, which is explained in the `README`.


First, `bsconfig.json`. The file tells [BuckleScript](https://bucklescript.github.io/) how to handle the compilation to JavaScript:

```json
{
  "name": "reason-music-player",
  "reason": {
    "react-jsx": 3
  },
  "sources": {
    "dir": "src",
    "subdirs": true
  },
  "package-specs": [
    {
      "module": "es6", // *new*: use ES6 imports
      "in-source": true
    }
  ],
  "suffix": ".bs.js",
  "namespace": true,
  "bs-dependencies": ["reason-react"],
  "refmt": 3
}
```

Our `package.json` looks familiar to JavaScript developers. We'll install [concurrently](https://www.npmjs.com/package/concurrently) to run both webpack and Bucklescript together:

```bash
npm i --save-dev concurrently
```

Adjust the script section in `package.json`:

```json
scripts": {
    "start": "concurrently -k \"npm run start:bsb\" \"npm run start:webpack\"",
    "start:bsb": "bsb -clean-world -make-world -w",
    "start:webpack": "webpack-dev-server --port 3000",
    "build": "npm run build:webpack",
    "build:webpack": "NODE_ENV=production webpack",
    "format": "refmt src/*.re"
  },
```

We'll also need a configuration file for [webpack][webpack]:

```js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const outputDir = path.join(__dirname, 'build/')

const isProd = process.env.NODE_ENV === 'production'

module.exports = {
  entry: './src/Index.bs.js',
  mode: isProd ? 'production' : 'development',
  output: {
    path: outputDir,
    filename: 'Index.js',
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      favicon: './src/favicon.ico',
      inject: false,
    }),
  ],
  devServer: {
    compress: true,
    contentBase: outputDir,
    port: process.env.PORT || 8000,
    historyApiFallback: true,
  },
}
```

Now we can run the project in the terminal and see it on `https://localhost:3000`:

```bash
npm run start
```

The example project comes with example components, which we'll delete. Only keep `src/Index.re`.

Open the `index.html` file and replace the content:

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css"
    />
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.2/css/fontawesome.min.css"
    />
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.2/css/solid.min.css"
    />
    <title>Reason Music Player</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="Index.js"></script>
  </body>
</html>
```

Now we are also able to use [Bulma CSS](https://bulma.io/) and [Font Awesome Icons](https://fontawesome.com/start).

We'll also modify `src/Index.re`:

```reasonml
ReactDOMRe.renderToElementWithId(<App />, "root");
```

Our index component will now render the `App` component into the HTML `div` with id "root". We'll see an error because the `App` component doesn't exist yet.

Let's create it:  
`src/App.re`

```reasonml

[@react.component]
let make = () => <div />
```

The syntax looks a bit strange. Every ReasonReact component has a `make` function, which creates a React element.  
ReasonReact uses functional components and [React hooks](https://reactjs.org/docs/hooks-reference.html) under the hood.  
Check the [ReasonReact documentation](https://reasonml.github.io/reason-react/docs/en/components) for further details.

We'll create a helper function to render strings in JSX:  
`src/ReactUtils.re`

```reasonml
external s: string => React.element = "%identity";
```

(Check [Florian Hammerschmidt's post on dev.to for further information][reasonbestpractices].)

Now, let's update our `App` component:

```reasonml
open ReactUtils; // (A)

[@react.component]
let make = () =>
  <div className="section is-fullheignt">
    <div className="container">
      <div className="column is-6 is-offset-4">
        <h1 className="is-size-2 has-text-centered">
          {s("Reason Music Player")}    // (A)
        </h1>
        <br />
      </div>
    </div>
  </div>;

```

We import the utility module, and now we can render a string (see `A`). Reason is type-safe, so you'll have to tell the program that you want to pass a string inside JSX.  
The `className`s are Bulma's way of styling.

## Recap

We installed Reason and BuckleScript and set up the bare minimum for our project.

ReasonReact and BuckleScript offer a familiar tooling experience for JavaScript developers. But we've already seen some differences between ReasonML and JavaScript (syntax, being explicit about rendering strings).

### Further Reading

- [How to Use the useContext Hook in React][upmostly] by James King
- [ReasonReact][reasonreact]
- [Reason(React) Best Practices - Part 1][reasonbestpractices]

[demo]: https://sophiabrandt.github.io/reason-music-player/
[repo]: https://github.com/sophiabrandt/reason-music-player
[upmostly]: https://upmostly.com/tutorials/how-to-use-the-usecontext-hook-in-react
[reasonbestpractices]: https://dev.to/fhammerschmidt/reason-react-best-practices-2cb7
[reasonreact]: https://reasonml.github.io/reason-react/
[webpack]: https://webpack.js.org/