Integrating P5.js with React
Tags: javascript, react, p5js
Published: 2020-02-13 22:04:27

In the course of my final project at the Flatiron School in software engineering, I really wanted to push my skills farther than what I was comfortable. We're given three weeks to accomplish a full-stack app in Rails and React, so I was looking for an idea that combines what I'd learned in the last 15 weeks as well as something I was aching to do. I'd toyed around with P5.js, a slick animation library for the browser (see prior blog post), and had seen different creators make some pretty cool [audio visualizers](https://tympanus.net/codrops/2018/03/06/creative-audio-visualizers/). 

Thankfully, through some other internet perusing, I'd settled on the idea to integrate p5.js and websockets to enable users to create audio visualizers collaboratively on the same canvases. You can read (and soon see the deployed project) on my [personal site](http://christianmkastner.com/). 

However, for the purposes of this post another blog post to come, I wanted to talk a little bit about how I was able to wrangle the disparate technologies to make my project possible. 

###Give Me All The Libraries

Coming from projects that were thought up, planned out, and built all within the course of a week, I'd learned to leaned on libraries to most of the heavy lifting for me. So my first instinct to make P5.js, and actioncable for websocketing, work was to look for some open source library that integrates the two with my React frontend. Although projects can be a blessing and make your job much easier, I learned very quickly that best option is to actually just learn the tech and not treat it like a black box. 

In the case of P5, a couple people had written nice libraries to have your sketches play nice with React, such as [P5-React](https://www.npmjs.com/package/react-p5) and [P5-React-Wrapper](https://www.npmjs.com/package/react-p5-wrapper). These are definitely nice for a very surface level implementation, like maybe a nice background image with some animations or something else to just spruce up your website. 

However, you aren't aware of what is happening under the hood for these pre-written components such that anything more complicated in P5 is liable to break the code or cause you some head scratching bugs. In my case, I needed to have the sketch respond to incoming data through the websocket and alter the sketch on the fly. Essentially, I had to mount a websocket cable inside the P5.js sketch. I'm assuming a base understanding of how sketching in P5 works, but the point I'm attempting to make here is that libraries are limited in their ability to suit the project you're working on. The problem I ran into was very case specific but it required full control over React, the websocket, and the P5 sketch. Essentially, I'd learned that when strapped for time, using a somebody's pre-written library, component, or whatever is probably a good idea. But if time permits or your problem requires that you need full control over your project, then you gotta go the long way and learn what you're doing.

###Now For How to Do it

Once I'd discarded the components referenced above, then all you need to do is create a dependency for P5 as a node package, running this in the terminal:

```
npm i p5
```

while in the relevant directory for your React project.

This just lets us access the good stuff p5 has to offer. Next, P5 can either be created in a global or instance. What that difference amounts to is whether we want P5 in node or interacting with the DOM or [window object](https://developer.mozilla.org/en-US/docs/Web/API/Window). Seeing that React has its own virtual DOM and getting P5 to play nice, P5 in instance mode is our way to go. 

Essentially, we're just creating a P5 object or instance that contains all the variables declared inside it, so as to not dilute our global namespace. This looks like:

```Javascript
const s = ( sketch ) => {

  let x = 100;
  let y = 100;

  sketch.setup = () => {
    sketch.createCanvas(200, 200);
  };

  sketch.draw = () => {
    sketch.background(0);
    sketch.fill(255);
    sketch.rect(x,y,50,50);
  };
};

let myp5 = new p5(s);
```

I've taken this from the [processing/p5.js github](https://github.com/processing/p5.js/wiki/Global-and-instance-mode). See this for more details on instance mode. But essentially we're encapsulating our sketch in a function that takes in a P5 sketch object that has access to all the P5 functions we like (such as setup, draw, background, etc. etc.). This just means that anything within P5 that we'd like to use must be accessed in the pattern of [name of sketch].[name of p5 function we want]. Anything outside of that, like variables or what have you will not change. 

This means that there is no loss between P5 manipulating the DOM directly and P5 in instance mode, we just have to annoyingly declare the functions or P5 variables in the sketch object. 

###Now to React

You have some leeway in how you integrate your sketch into the component you want. I needed it to create a canvas that users could add, edit, or delete shapes on, so mine lived in a "canvas" component. Looking like this:

```Javascript
class App extends React.Component {
  constructor(props) {
    super(props)
    this.myRef = React.createRef()
  }

  Sketch = (p) => {

     p.setup = () => {
     ...
     }

     p.draw = () => {
     ...
     }
  }
...
```

To distill the way I made this work with React, I've stripped away the things I'm doing in the sketch just to show exactly how the syntax and P5 functions work within the component. But the setup and draw functions work exactly as they do in regular P5. The naming is different than the instance object shown above, but the names do not matter whatsoever. "s" has become "Sketch" and the P5 sketch object has been named "p" so that I don't have to keep typing the same long word over and over again to reference P5 functions and variables. 

Finally, to have our instance P5 attach to the DOM in react we have to give it some reference node to stand as its parent. Luckily, React has given us the ability to do this, as seen by 
```Javascript
this.myRef = React.createRef()
```
in the constructor of our component. We will use this reference node to attach whatever we want for our P5 sketch. I declare the creation of the new P5 object and the reference node in the componentDidMount lifecycle method so that mounting kicks off the attachment of my P5 sketch. All together this looks like 

```Javascript
class App extends React.Component {
  constructor(props) {
    super(props)
    this.myRef = React.createRef()
  }

  Sketch = (p) => {

     p.setup = () => {
     ...
     }

     p.draw = () => {
     ...
     }
  }

  componentDidMount() {
    this.myP5 = new p5(this.Sketch, this.myRef.current)
  }

  render() {
    return (
      <div ref={this.myRef}>

      </div>
    )
  }
}

```

And voila! We created a reference node in our constructor function called "this.myRef". We save our sketch in a function that takes in a P5 sketch object. We declare the creation of a new p5 object, giving it our function, and the reference node (the second argument is reserved for such a node instance). Then in our render, we have a div that is the reference node we declared in the constructor. Bada bing, bada boom, the P5 sketch is attached to the div in our render function, and P5 is totally integrated with React. No pre-made components. This allows for total control of our sketch within React. All it took was taking advantage of the instance mode of P5 and the creation of a reference node in React.

You can see exactly my implementation on my github, and I'll be sure to go into detail about how I used actioncable to mount a websocket connection within my sketch on a future blog post.