百科.dev
全部条目AI 编程趋势榜开源项目技术资讯提交条目
登录
< 返回工具列表
W

wasm-react

> 前端框架
开源

用于 React 的 WASM 绑定。

100 stars0 点赞1 次浏览
访问官网GitHub

工具介绍

用于 React 的 WASM 绑定。

wasm-react ⚛️

WASM bindings for React.

Introduction

This library enables you to write and use React components in Rust, which then can be exported to JS to be reused or rendered.

Why React?

React is one of the most popular UI framework for JS with a thriving community and lots of libraries written for it. Standing on the shoulder of giants, you will be able to write complex frontend applications with Rust.

Goals

  • Provide Rust bindings for the public API of react as close to the original API as possible, but with Rust in mind.
  • Provide an ergonomic way to write components.
  • Provide ways to interact with components written in JS.

Non-Goals

  • Provide bindings for any other library than react, e.g. react-dom.
  • Reimplementation of the reconciliation algorithm or runtime.
  • Emphasis on performance.

Getting Started

Make sure you have Rust and Cargo installed. You can install wasm-react with cargo. Furthermore, if you want to expose your Rust components to JS, you also need wasm-bindgen and have wasm-pack installed.

bash
$ cargo add wasm-react
$ cargo add [email protected]

Creating a Component

First, you need to define a struct for the props of your component. To define the render function, you need to implement the trait Component for your struct:

rust
use wasm_react::{h, Component, VNode};

struct Counter {
  counter: i32,
}

impl Component for Counter {
  fn render(&self) -> VNode {
    h!(div)
      .build((
        h!(p).build(("Counter: ", self.counter)),
        h!(button).build("Increment"),
      ))
  }
}

Add State

You can use the use_state() hook to make your component stateful:

rust
use wasm_react::{h, Component, VNode};
use wasm_react::hooks::use_state;

struct Counter {
  initial_counter: i32,
}

impl Component for Counter {
  fn render(&self) -> VNode {
    let counter = use_state(|| self.initial_counter);

    let result = h!(div)
      .build((
        h!(p).build(("Counter: ", *counter.value())),
        h!(button).build("Increment"),
      ));
    result
  }
}

Note that according to the usual Rust rules, the state will be dropped when the render function returns. use_state() will prevent that by tying the lifetime of the state to the lifetime of the component, therefore persisting the state through the entire lifetime of the component.

Add Event Handlers

To create an event handler, you pass a Callback created from a Rust closure. You can use the helper macro clones! to clone-capture the environment more ergonomically.

…

Export Components for JS Consumption

First, you'll need wasm-pack. You can use export_components! to export your Rust component for JS consumption. Requirement is that your component implements TryFrom.

rust
use wasm_react::{h, export_components, Component, VNode};
use wasm_bindgen::JsValue;

struct Counter {
  initial_counter: i32,
}

impl Component for Counter {
  fn render(&self) -> VNode {
    /* … */
    VNode::new()
  }
}

struct App;

impl Component for App {
  fn render(&self) -> VNode {
    h!(div).build((
      Counter {
        initial_counter: 0,
      }
      .build(),
    ))
  }
}

impl TryFrom for App {
  type Error = JsValue;

  fn try_from(_: JsValue) -> Result {
    Ok(App)
  }
}

export_components! { App }

Use wasm-pack to compile your Rust code into WASM:

bash
$ wasm-pack build

Depending on your JS project structure, you may want to specify the --target option, see wasm-pack documentation.

Assuming you use a bundler that supports JSX and WASM imports in ES modules like Webpack, you can use:

javascript
import React from "react";
import { createRoot } from "react-dom/client";

async function main() {
  const { WasmReact, App } = await import("./path/to/pkg/project.js");
  WasmReact.useReact(React); // Tell wasm-react to use your React runtime

  const root = createRoot(document.getElementById("root"));
  root.render();
}

If you use plain ES modules, you can do the following:

bash
$ wasm-pack build --target web
javascript
import "https://unpkg.com/react/umd/react.production.min.js";
import "https://unpkg.com/react-dom/umd/react-dom.production.min.js";
import init, { WasmReact, App } from "./path/to/pkg/project.js";

async function main() {
  await init(); // Need to load WASM first
  WasmReact.useReact(window.React); // Tell wasm-react to use your React runtime

  const root = ReactDOM.createRoot(document.getElementById("root"));
  root.render(React.createElement(App, {}));
}

Import Components for Rust Consumption

You can use import_components! together with wasm-bindgen to import JS components for Rust consumption. First, prepare your JS component:

javascript
// /.dummy/myComponents.js
import "https://unpkg.com/react/umd/react.production.min.js";

export function MyComponent(props) {
  /* … */
}

Make sure the component uses the same React runtime as specified for wasm-react. Afterwards, use import_components!:

rust
use wasm_react::{h, import_components, Component, VNode};
use wasm_bindgen::prelude::*;

import_components! {
  #[wasm_bindgen(module = "/.dummy/myComponents.js")]

  MyComponent
}

struct App;

impl Component for App {
  fn render(&self) -> VNode {
    h!(div).build((
      MyComponent::new()
        .attr("prop", &"Hello World!".into())
        .build(()),
    ))
  }
}

Passing Down Non-Copy Props

Say you define a component with the following struct:

rust
use std::rc::Rc;

struct TaskList {
  tasks: Vec>
}

You want to include TaskList in a container component App where tasks is managed by a state:

rust
use std::rc::Rc;
use wasm_react::{h, Component, VNode};
use wasm_react::hooks::{use_state, State};

struct TaskList {
  tasks: Vec>
}

impl Component for TaskList {
  fn render(&self) -> VNode {
    /* … */
    VNode::default()
  }
}

struct App;

impl Component for App {
  fn render(&self) -> VNode {
    let tasks: State>> = use_state(|| vec![]);

    h!(div).build((
      TaskList {
        tasks: todo!(), // Oops, `tasks.value()` does not fit the type
      }
      .build(),
    ))
  }
}

Changing the type of tasks to fit tasks.value() doesn't work, since tasks.value() returns a non-'static reference while component structs can only contain 'static values. You can clone the underlying Vec, but this introduces unnecessary overhead. In this situation you might think you can simply change the type of TaskList to a State:

rust
use std::rc::Rc;
use wasm_react::{h, Component, VNode};
use wasm_react::hooks::{use_state, State};

struct TaskList {
  tasks: State>>
}

This works as long as the prop tasks is guaranteed to come from a state. But this assumption may not hold. You might want to pass on Rc>> or Memo>> instead in the future or somewhere else. To be as generic as possible, you can use PropContainer:

…

Known Caveats

  • Rust components cannot be part of the subtree of a StrictMode component.

    wasm-react uses React hooks to manually manage Rust memory. StrictMode will run hooks and their destructors twice which will result in a double free.

License

Licensed under either of

  • Apache License, Version 2.0 (LICENSE-APACHE or )
  • MIT license (LICENSE-MIT or )

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Issues· 0 开放

查看全部 Issues在 GitHub 打开

暂无开放 Issues,或尚未同步最近议题。

> 标签

Rustjavascriptjsreactrust

暂无评论,来聊聊你的看法吧

> 工具信息

发布日期2026年8月1日
最后更新2026年9月18日
分类前端框架
定价开源

> 相关工具

R
React
用于构建用户界面的 JavaScript 库
V
Vue.js
渐进式 JavaScript 框架
N
Next.js
基于 React 的全栈 Web 框架