Skip to content

Commit ac87997

Browse files
committed
feat: React.useState
1 parent cfa19e4 commit ac87997

File tree

5 files changed

+169
-112
lines changed

5 files changed

+169
-112
lines changed

src/helpers.rs

Lines changed: 0 additions & 112 deletions
This file was deleted.

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
mod element;
22
mod macro_import;
3+
mod use_state;
4+
35
pub use element::*;
6+
pub use use_state::*;

src/use_state/helpers.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
use super::macro_helpers::*;
2+
pub use std::{concat, stringify};
3+
4+
use wasm_bindgen::prelude::*;
5+
6+
define_react_use_state_helpers! {
7+
{
8+
value: bool,
9+
object: UseStateBoolObject,
10+
setter: UseStateBoolObjectSetter,
11+
use_state: use_state_bool,
12+
use_state_with: use_state_bool_with,
13+
auto_clean: use_state_bool_auto_clean,
14+
auto_clean_with: use_state_bool_auto_clean_with,
15+
},
16+
{
17+
value: usize,
18+
object: UseStateUsizeObject,
19+
setter: UseStateUsizeObjectSetter,
20+
use_state: use_state_usize,
21+
use_state_with: use_state_usize_with,
22+
auto_clean: use_state_usize_auto_clean,
23+
auto_clean_with: use_state_usize_auto_clean_with,
24+
},
25+
{
26+
value: i32,
27+
object: UseStateI32Object,
28+
setter: UseStateI32ObjectSetter,
29+
use_state: use_state_i32,
30+
use_state_with: use_state_i32_with,
31+
auto_clean: use_state_i32_auto_clean,
32+
auto_clean_with: use_state_i32_auto_clean_with,
33+
},
34+
}

src/use_state/macro_helpers.rs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#[cfg(feature = "import-react")]
2+
macro_rules! wasm_bindgen_react_state_helpers {
3+
($($b:item)+) => {
4+
#[wasm_bindgen(inline_js = r#"
5+
import * as React from "react";
6+
export { React };
7+
export function use_state_object(initial_value) {
8+
const [state, set_state] = React.useState(initial_value);
9+
return { value: state, setter: { set_state } };
10+
}
11+
export function use_state_auto_clean(initial_value, clean) {
12+
const obj = use_state_object(initial_value);
13+
const state = obj.value;
14+
React.useEffect(() => { clean(state) }, [state]);
15+
}
16+
"#)]
17+
extern "C" {
18+
$($b)+
19+
}
20+
};
21+
}
22+
23+
#[cfg(not(feature = "import-react"))]
24+
macro_rules! wasm_bindgen_react_state_helpers {
25+
($($b:item)+) => {
26+
#[wasm_bindgen(inline_js = r#"
27+
export function use_state_object(initial_value) {
28+
const [state, set_state] = React.useState(initial_value);
29+
return { value: state, setter: { set_state } };
30+
}
31+
export function use_state_auto_clean(initial_value, clean) {
32+
const obj = use_state_object(initial_value);
33+
const state = obj.value;
34+
React.useEffect(() => { clean(state) }, [state]);
35+
}
36+
"#)]
37+
extern "C" {
38+
$($b)+
39+
}
40+
};
41+
}
42+
43+
macro_rules! define_react_use_state_for_type {
44+
( { value: $type_value:ty, $($t:tt)+ } ) => {
45+
define_react_use_state_for_type! {{
46+
input: $type_value,
47+
output: $type_value,
48+
$($t)+
49+
}}
50+
};
51+
({
52+
input: $type_input:ty,
53+
output: $type_output:ty,
54+
object: $name_object:ident,
55+
setter: $name_setter:ident,
56+
use_state: $name_use:ident,
57+
use_state_with: $name_use_with:ident,
58+
auto_clean: $name_clean:ident,
59+
auto_clean_with: $name_clean_with:ident
60+
$(,)?
61+
}) => {
62+
wasm_bindgen_react_state_helpers! {
63+
#[derive(Debug, Clone)]
64+
pub type $name_object;
65+
#[wasm_bindgen(structural, method, getter)]
66+
fn value(this: &$name_object) -> $type_output;
67+
#[wasm_bindgen(structural, method, getter)]
68+
fn setter(this: &$name_object) -> $name_setter;
69+
70+
#[derive(Debug, Clone)]
71+
pub type $name_setter;
72+
#[wasm_bindgen(structural, method)]
73+
fn set_state(this: &$name_setter, value: $type_input);
74+
/// Closure `get_value_from_old` will be called immediately,
75+
/// thus it is safe to use reference here
76+
///
77+
/// Closure get_value_from_old will be called only once
78+
#[wasm_bindgen(structural, method, js_name = "set_state")]
79+
fn set_state_with(
80+
this: &$name_setter,
81+
get_value_from_old: &mut dyn FnMut($type_output) -> $type_input,
82+
);
83+
84+
/// `React.useState<T>(initial_value)`
85+
#[wasm_bindgen(js_name = "use_state_object")]
86+
fn $name_use(initial_value: $type_input) -> $name_object;
87+
88+
/// `React.useState<T>(get_initial_value)`
89+
#[wasm_bindgen(js_name = "use_state_object")]
90+
#[doc = concat!("React.useState<`", stringify!($type_input), "`>(initial_value)")]
91+
fn $name_use_with(
92+
initial_value: &mut dyn FnMut() -> $type_input,
93+
) -> $name_object;
94+
95+
#[wasm_bindgen(js_name = "use_state_auto_clean")]
96+
fn $name_clean(
97+
initial_value: $type_input,
98+
free: &Closure<dyn FnMut($type_output)>,
99+
) -> $name_object;
100+
101+
#[wasm_bindgen(js_name = "use_state_auto_clean")]
102+
fn $name_clean_with(
103+
get_initial_value: &mut dyn FnMut() -> $type_input,
104+
free: &Closure<dyn FnMut($type_output)>,
105+
) -> $name_object;
106+
}
107+
};
108+
}
109+
110+
macro_rules! define_react_use_state_helpers {
111+
($($t:tt),+ $(,)?) => {
112+
$( define_react_use_state_for_type!{ $t } )+
113+
};
114+
}
115+
116+
pub(super) use define_react_use_state_for_type;
117+
pub(super) use define_react_use_state_helpers;
118+
pub(super) use wasm_bindgen_react_state_helpers;

src/use_state/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
mod macro_helpers;
2+
3+
mod helpers;
4+
pub use helpers::*;
5+
6+
use wasm_bindgen::prelude::*;
7+
8+
crate::macro_import::wasm_bindgen_react! {
9+
#[wasm_bindgen(js_namespace = React, js_name = useState)]
10+
pub fn use_state(initial_state: JsValue) -> Box<[JsValue]>;
11+
12+
#[wasm_bindgen(js_namespace = React, js_name = useState)]
13+
pub fn use_state_with(initial_state: &mut dyn FnMut() -> JsValue) -> Box<[JsValue]>;
14+
}

0 commit comments

Comments
 (0)