Create a WebAssembly app with React and Go
Tags: react, webassembly, go
Published: 2019-09-06 01:16:19

# Getting started with WASM, React and Go

WebAssembly is awesome --barely a news, but how can you use it with React and Go? Well, honestly there are materials out there that are good to help to figure this out. But personally, it wasnt a smooth experience. I wanted a straightforward, up-to-date article. For one, I was looking for a solution that used Create-React-App because who wants to mess with Webpack? 🙃🙃

The aim of this short and simple tutorial is to show you how I pieced everything together and have a React based Go program compiled to WebAssembly up and running. I'd assume the following:
 * You have Go installed (1.11 and above).
 * Npm/Yarn installed.

So lets get to it.

In this tutorial, we'll enter a value into the input box in react and then use WebAssembly to render this value. Simple and interesting, right?

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/h4h0ur2eaig2lvjy0hkf.png)

Clone the repo [here](https://github.com/oayomide/go-reactive). The repo contains the ejected app. I am trying to make this article as brief as possible so I might (unintentionally) miss some things.

In the root, we have `main.go` that contains the following code:
```go
package main

import (
	"fmt"
	"syscall/js"
)

var c chan bool

// init is called even before main is called. This ensures that as soon as our WebAssembly module is ready in the browser, it runs and prints "Hello, webAssembly!" to the console. It then proceeds to create a new channel. The aim of this channel is to keep our Go app running until we tell it to abort.
func init() {
	fmt.Println("Hello, WebAssembly!")
	c = make(chan bool)
}

func main() {
    // here, we are simply declaring the our function `sayHelloJS` as a global JS function. That means we can call it just like any other JS function.
	js.Global().Set("sayHelloJS", js.FuncOf(SayHello))
    println("Done.. done.. done...")
    
    // tells the channel we created in init() to "stop".
	<-c
}

// SayHello simply set the textContent of our element based on the value it receives (i.e the value from the input box)
// the element MUST exist else it'd throw an exception
func SayHello(jsV js.Value, inputs []js.Value) interface{} {
	message := inputs[0].String()
	h := js.Global().Get("document").Call("getElementById", "message")
	h.Set("textContent", message)
	return nil
}
```

Our function sayHello takes two arguments. We're more concerned with the second. What the second does essentially is that it takes an array of js.Value. This is because we can pass as many argument as we want from JavaScript. To get the values, we simply use the index. So, in our case, we want to get the value entered in the input box.

```go
message := inputs[0].String()
```
Like I said earlier, we use the index of the array to get the value of whatever we want.

```go
h := js.Global().Get("document").Call("getElementById", "message")
h.Set("textContent", message)
```
the above code is similar to:
```js
let h = document.getElementById("message")
h.textContent = message
```
So what we're doing is that we're changing the text of our element with the id "message" with the input value.

Run the following to compile the `main.go`:
```bash
GOOS=js GOARCH=wasm go build -o ../client/public/main.wasm
```

### Client side of things
In the `App.js`, we have this in the componentDidMount():
```js
async componentDidMount() {
    let { instance, module } = await WebAssembly.instantiateStreaming(fetch("main.wasm"), window.go.importObject)
    await window.go.run(instance)
    this.setState({
      mod: module,
      inst: instance
    })
  }
```
We're instantiating our `main.wasm` and running the instance. That means we can now go ahead and call our WASM functions in our app. Also, setting the module and instance to state incase we need them later on. Also, **you'd notice that we're doing `window.go.run(instance)`.** Where did it come from? Well, its already handled in the React app. You'd notice there is a `wasmjs` folder which contains an `init_js` file. This and the `wasm_exec.js` file needed to use our WASM file with JS have been created and bundled with our React App using webpack. **So it binds the Go() instance to the global window. Therefore instead of declaring a new instance of Go(), it exists as a window object variable**

```js
 handleSubmit = async (e) => {
    e.preventDefault()
    window.sayHelloJS(this.state.message)
  }
```
and this is us calling our function sayHelloJS that we registered in our Go code earlier! Notice we're accessing as a window object property. This is because we're calling it from React. It's going to be undefined if we called it as `sayHelloJS`.
```html
<span id="message">
    Ayomide Onigbinde wrote this!!😉...💕 from WebAssembly and Golang
</span>
```
We have this HTML element. Note that it has an id "message". This element was the one we manipulated in our Go code which we compiled to WebAssembly! So this element must exist else it'd throw an exception. This is what will change into whatever value we enter in the input box! And its WebAssembly (compiled from Go) doing this! 🎉🎉

I tried to explain as best as I could! Please if there's something not clear, comment and we'd figure it out together 😉😉.

Huge props to Aaron for his [tutorial](https://www.aaron-powell.com/posts/2019-02-06-golang-wasm-3-interacting-with-js-from-go/) and big big thanks to [Chris at LogRocket](https://github.com/Chrischuck/ai-tic-tac-toe/tree/master/client/src). It was a huuuggeee help! [This Dev.to article](https://dev.to/brightdevs/using-webassembly-with-react-1led) also helped to get an understanding about React with WASM.

<!-- ## Golang side of things
First, we want to write a simple Go code. Create a `main.go` file and add the following:
    
```go
import (
    "fmt"
)

func main() {
    fmt.Println("Hello, WASM!")
}
```

then run the following command in your terminal:
```bash
GOOS=js GOARCH=wasm go build -o main.wasm
```
You can replace `main` with anything you want.
This command would create a `main.wasm` file. This is the meat!

## React of things
Create a new folder `client` and `cd` into it. Then create a new React app. If you have `npx` installed, simply do:
```bash
npx create-react-app .
```

Then eject your app:
```yarn eject```

Then we want to install the  -->