pub trait ReactAppExt {
// Required methods
fn add_react_message<T>(&mut self) -> &mut Self
where T: ReactPayload,
for<'a> <T as Event>::Trigger<'a>: Default;
fn add_react_handler<E, B, M, S>(&mut self, observer: S) -> &mut Self
where E: ReactPayload,
for<'a> <E as Event>::Trigger<'a>: Default,
B: Bundle,
S: IntoObserverSystem<E, B, M>;
fn add_react_request<T>(&mut self) -> &mut Self
where T: ReactRequest;
fn add_react_request_handler<E, B, M, S>(
&mut self,
observer: S,
) -> &mut Self
where E: Event + RequestEvent,
for<'a> <E as Event>::Trigger<'a>: Default,
B: Bundle,
S: IntoObserverSystem<E, B, M>;
fn add_react_event<E>(&mut self) -> &mut Self
where E: ReactEvent;
fn export_react_typescript(&self, path: impl AsRef<Path>) -> Result<()>;
}Expand description
Registers typed React message payloads on a Bevy App.
Required Methods§
Sourcefn add_react_message<T>(&mut self) -> &mut Self
fn add_react_message<T>(&mut self) -> &mut Self
Register a typed React message payload without attaching an observer.
After this, an emit(T::NAME, value) from the React app deserializes
value into T and triggers it. Prefer add_react_handler
unless you want to register the type and observe it separately.
Sourcefn add_react_handler<E, B, M, S>(&mut self, observer: S) -> &mut Selfwhere
E: ReactPayload,
for<'a> <E as Event>::Trigger<'a>: Default,
B: Bundle,
S: IntoObserverSystem<E, B, M>,
fn add_react_handler<E, B, M, S>(&mut self, observer: S) -> &mut Selfwhere
E: ReactPayload,
for<'a> <E as Event>::Trigger<'a>: Default,
B: Bundle,
S: IntoObserverSystem<E, B, M>,
Register a payload and attach an observer for it in one call.
The payload type is inferred from the observer’s On<T> parameter, so you
never name it twice. Call it again with another observer to add more
handlers for the same message — registration is idempotent.
app.add_react_handler(|count: On<Count>, mut desired: ResMut<DesiredCubes>| {
desired.0 = count.event().0;
});Sourcefn add_react_request<T>(&mut self) -> &mut Selfwhere
T: ReactRequest,
fn add_react_request<T>(&mut self) -> &mut Selfwhere
T: ReactRequest,
Register a typed React request without attaching an observer. Prefer
add_react_request_handler.
Sourcefn add_react_request_handler<E, B, M, S>(&mut self, observer: S) -> &mut Selfwhere
E: Event + RequestEvent,
for<'a> <E as Event>::Trigger<'a>: Default,
B: Bundle,
S: IntoObserverSystem<E, B, M>,
fn add_react_request_handler<E, B, M, S>(&mut self, observer: S) -> &mut Selfwhere
E: Event + RequestEvent,
for<'a> <E as Event>::Trigger<'a>: Default,
B: Bundle,
S: IntoObserverSystem<E, B, M>,
Register a request and attach its observer in one call.
The request type is inferred from the observer’s On<Request<T>> parameter.
The observer answers the request via Request::respond.
app.add_react_request_handler(|req: On<Request<BoardGet>>, board: Res<Board>| {
req.respond(board.clone());
});Sourcefn add_react_event<E>(&mut self) -> &mut Selfwhere
E: ReactEvent,
fn add_react_event<E>(&mut self) -> &mut Selfwhere
E: ReactEvent,
Register a Bevy → React event type so it appears in the generated
ReactEvents map and bevy.on typing. Sending an event with
ReactEvents does not require this, but then the type
won’t be known to the exporter.
Sourcefn export_react_typescript(&self, path: impl AsRef<Path>) -> Result<()>
fn export_react_typescript(&self, path: impl AsRef<Path>) -> Result<()>
Write a self-contained TypeScript module (conventionally src/bevy.ts)
mirroring every registered React binding to path.
The generated module covers all three app-messaging surfaces in one pass:
a type declaration per payload (mirrored from the #[react_message] /
#[react_request] / #[react_event] structs via ts-rs), the
ReactMessages/ReactRequests/ReactEvents name→type maps, typed
emit/request/on wrappers, and a structured bevy proxy whose nested
methods come from dotted request names ("board.get" → bevy.board.get()).
App code imports that typed surface from ./bevy instead of the untyped
functions from "bevy-react", so every call is checked against the same
structs Bevy serializes and deserializes.
Keep a single registration site: put your add_react_* calls in a
register_bindings(app) function that both the real app (e.g. your
plugin’s build) and a small exporter entry point call, so a binding can
never exist at runtime without appearing in the generated types. Wire the
exporter to a CLI flag that returns before app.run(), commit the output,
and have CI regenerate + git diff --exit-code to guarantee the
TypeScript never drifts from Rust. (See examples/demos/main.rs and its
--export-bindings flag, exposed as npm run bevy:generate.)
if std::env::args().nth(1).as_deref() == Some("--export-bindings") {
let path = std::env::args().nth(2).expect("output path");
let mut app = App::new();
register_bindings(&mut app); // the same fn the real app calls
app.export_react_typescript(&path)?;
return;
}Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".