React + Rust + Wasm: DOM Manipulation

Neo Quest | Nikhil Gupta

Neo Quest | Nikhil Gupta / October 23, 2022

3 min read

Summary

In this article, we will manipulate the DOM in our React application from our Rust WASM library. We will build on the previous tutorial available here.

Add web-sys to our Rust dependencies

We will use web-sys to interact with the DOM. Let's add it to our Cargo.toml and activate associated features:

# Cargo.toml

[package]
name = "rust-wasm-lib"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2.83"

[dependencies.web-sys]
version = "0.3.4"
features = [
  'Document',
  'Element',
  'HtmlElement',
  'Node',
  'Window',
]

DOM Manipulation using Rust

Last time, we exposed a function to add two numbers in Rust but the result was added to the screen in the react app. Now, let's modify our lib.rs to expose another function that will automatically show the result on screen.

#[wasm_bindgen]
pub fn addAndShow(a: i32, b: i32) -> Result<(), JsValue> {
  let window = web_sys::window().expect("no global `window` exists");
  let document = window.document().expect("should have a document on window");
  let body = document.body().expect("document should have a body");

  let element = document.create_element("p")?;
  element.set_text_content(Some(&format!("{} + {} = {}", a, b, a + b)));

  body.append_child(&element)?;

  Ok(())
}

Let's go through the code step-by-step.

  • Expose a function called addAndShow that takes two integers and returns a Result
  • Get the global window using web_sys API
  • Get the document from this window
  • Get the body for this document
  • Create a DOM element with a p tag
  • Set the text to be the equation a + b = c using the format macro
  • Append the element to the body
  • Set the Result to success

Build the new wasm library

Let's run wasm-pack again to build the updated library

wasm-pack build --target web

Call the new function from the demo app

Finally, let's call the exported addAndShow function from our App.ts file like so:

// App.ts

import React, { useEffect } from 'react';
import init, { addAndShow } from "rust-wasm-lib";
import './App.css';

function App() {
  useEffect(() => {
    init().then(() => {
      addAndShow(3, 4);
    });
  }, [])

  return (
    <div className="App">
    </div>
  );
}

export default App;

Now, if you run the updated app, you should see 3 + 4 = 7 on the screen. :)

If you see it twice, you can disable the <React.StrictMode> from index.tsx that calls the useEffect block twice.