|
@@ -0,0 +1,220 @@
|
|
|
+//! <div align="center">
|
|
|
+//! <h1>🌗🚀 📦 Dioxus</h1>
|
|
|
+//! <p>
|
|
|
+//! <strong>A concurrent, functional, virtual DOM for Rust</strong>
|
|
|
+//! </p>
|
|
|
+//! </div>
|
|
|
+//! Dioxus: a concurrent, functional, reactive virtual dom for any renderer in Rust.
|
|
|
+//!
|
|
|
+//! This crate aims to maintain a hook-based, renderer-agnostic framework for cross-platform UI development.
|
|
|
+//!
|
|
|
+//! ## Overview and Goals
|
|
|
+//! Dioxus' ultimate goal is to save you from writing new code when bringing your application to new platforms. We forsee
|
|
|
+//! a future where WebApps, Mobile Apps, Desktop Apps, and even AR apps can be written in the same language, ecosystem,
|
|
|
+//! and leverage the same platform-agnostic libraries.
|
|
|
+//!
|
|
|
+//! In this aim we chose to use a variety of techniques:
|
|
|
+//! - We use a VirtualDOM to abstract the true renderer from application logic.
|
|
|
+//! - We use functions as components to limit the API churn for greater stability.
|
|
|
+//! - We use hooks as state to allow reusable logic across the whole ecosystem.
|
|
|
+//! - We support an extensible and compile-time safe DSL for building interfaces.
|
|
|
+//!
|
|
|
+//! Our guiding stars (in order of priority):
|
|
|
+//! - Ergonomics
|
|
|
+//! - Reusability
|
|
|
+//! - Speed and memory efficiency
|
|
|
+//! - Safety
|
|
|
+//!
|
|
|
+//! ## Components
|
|
|
+//! The base unit of Dioxus is the `component`. Components can be easily created from just a function - no traits or
|
|
|
+//! proc macros required:
|
|
|
+//!
|
|
|
+//! ```
|
|
|
+//! use dioxus::prelude::*;
|
|
|
+//!
|
|
|
+//! fn Example(ctx: Context<()>) -> VNode {
|
|
|
+//! html! { <div> "Hello, world!" </div> }
|
|
|
+//! }
|
|
|
+//! ```
|
|
|
+//! Components need to take a "Context" parameter which is generic over some properties. This defines how the component can be used
|
|
|
+//! and what properties can be used to specify it in the VNode output. Components without properties may be generic over
|
|
|
+//! `()`, and components with properties must declare their properties as a struct:
|
|
|
+//!
|
|
|
+//! ```
|
|
|
+//! #[derive(Props)]
|
|
|
+//! struct Props { name: String }
|
|
|
+//!
|
|
|
+//! fn Example(ctx: Context<Props>) -> VNode {
|
|
|
+//! html! { <div> "Hello {ctx.props.name}!" </div> }
|
|
|
+//! }
|
|
|
+//! ```
|
|
|
+//!
|
|
|
+//! Props that are valid for the `'static` lifetime automatically get memoized by Diouxs. This means the component won't
|
|
|
+//! re-render if its Props didn't change. However, Props that borrow data from their parent cannot be safely memoized, and
|
|
|
+//! will always re-render if their parent changes. To borrow data from a parent, your component needs to add explicit lifetimes,
|
|
|
+//! otherwise Rust will get confused about whether data is borrowed from either Props or Context. Since Dioxus manages
|
|
|
+//! these lifetimes internally, Context and your Props must share the same lifetime:
|
|
|
+//!
|
|
|
+//! ```
|
|
|
+//! #[derive(Props)]
|
|
|
+//! struct Props<'a> { name: &'a str }
|
|
|
+//!
|
|
|
+//! fn Example<'a>(ctx: Context<'a, Props<'a>>) -> VNode {
|
|
|
+//! html! { <div> "Hello {ctx.props.name}!" </div> }
|
|
|
+//! }
|
|
|
+//! ```
|
|
|
+//!
|
|
|
+//!
|
|
|
+//!
|
|
|
+//! The lifetimes might look a little messy, but are crucially important for Dioxus's efficiency and overall ergonimics.
|
|
|
+//! Components can also be crafted as static closures, enabling type inference without all the type signature noise. However,
|
|
|
+//! closure-style components cannot work with borrowed data, due to limitations in Rust's lifetime system.
|
|
|
+//!
|
|
|
+//! ```
|
|
|
+//! #[derive(Props)]
|
|
|
+//! struct Props { name: String }
|
|
|
+//!
|
|
|
+//! static Example: FC<Props> = |ctx| {
|
|
|
+//! html! { <div> "Hello {ctx.props.name}!" </div> }
|
|
|
+//! }
|
|
|
+//! ```
|
|
|
+//!
|
|
|
+//! To use custom properties for components, you'll need to derive the `Props` trait for your properties. This trait
|
|
|
+//! exposes a compile-time correct builder pattern (similar to typed-builder) that can be used in the `rsx!` and `html!`
|
|
|
+//! macros to build components. Component props may have default fields notated by the `Default` attribute:
|
|
|
+//!
|
|
|
+//! ```
|
|
|
+//! #[derive(Props)]
|
|
|
+//! struct Props {
|
|
|
+//! name: String
|
|
|
+//!
|
|
|
+//! #[props(default = false)]
|
|
|
+//! checked: bool,
|
|
|
+//!
|
|
|
+//! #[props(default, setter(strip_option, into))]
|
|
|
+//! title: Option<String>
|
|
|
+//! }
|
|
|
+//! ```
|
|
|
+//!
|
|
|
+//! These flags roughly follow that of typed-builder, though tweaked to support the `Props` usecase.
|
|
|
+//!
|
|
|
+//! ## Hooks and State
|
|
|
+//! Dioxus uses hooks for state management. Hooks are a form of state persisted between calls of the function component.
|
|
|
+//!
|
|
|
+//! ```
|
|
|
+//! static Example: FC<()> = |ctx| {
|
|
|
+//! let (val, set_val) = use_state(&ctx, || 0);
|
|
|
+//! ctx.render(rsx!(
|
|
|
+//! button { onclick: move |_| set_val(val + 1) }
|
|
|
+//! ))
|
|
|
+//! }
|
|
|
+//! ````
|
|
|
+//!
|
|
|
+//! Instead of using a single struct to represent a component and its state, hooks use the "use_hook" building block
|
|
|
+//! which allows the persistence of data between function component renders. This primitive is exposed directly through
|
|
|
+//! the `Context` item:
|
|
|
+//! ```
|
|
|
+//! fn my_hook<'a>(ctx: &impl Scoped<'a>) -> &'a String {
|
|
|
+//! ctx.use_hook(
|
|
|
+//! // Initializer stores a value
|
|
|
+//! || String::new("stored_data"),
|
|
|
+//!
|
|
|
+//! // Runner returns the hook value every time the component is rendered
|
|
|
+//! |hook| &*hook,
|
|
|
+//!
|
|
|
+//! // Cleanup runs after the component is unmounted
|
|
|
+//! |hook| log::debug!("cleaning up hook with value {:#?}", hook)
|
|
|
+//! )
|
|
|
+//! }
|
|
|
+//! ```
|
|
|
+//! Under the hood, hooks store their data in a series of "memory cells". The first render defines the layout of these
|
|
|
+//! memory cells, and on each subsequent render, each `use_hook` call accesses its corresponding memory cell. If a hook
|
|
|
+//! accesses the wrong memory cell, `use_hook` will panic, and your app will crash. You can always use `try_use_hook` but
|
|
|
+//! these types of errors can be easily mitigated by following the rules of hooks:
|
|
|
+//!
|
|
|
+//! - Don’t call Hooks inside loops, conditions, or nested functions
|
|
|
+//! - Don't call hooks in changing order between renders
|
|
|
+//!
|
|
|
+//! Hooks provide a very powerful way to reuse stateful logic between components, simplify large complex components,
|
|
|
+//! and adopt more clear context subscription patterns to make components easier to read. The mechanics of hooks in Dioxus
|
|
|
+//! shares a great amount of similarity with React's hooks and there are many guides to hooks in React online.
|
|
|
+//!
|
|
|
+//! ## Supported Renderers
|
|
|
+//! Instead of being tightly coupled to a platform, browser, or toolkit, Dioxus implements a VirtualDOM object which
|
|
|
+//! can be consumed to draw the UI. The Dioxus VDOM is reactive and easily consumable by 3rd-party renderers via
|
|
|
+//! the `Patch` object. See [Implementing a Renderer](docs/8-custom-renderer.md) and the `StringRenderer` classes for information
|
|
|
+//! on how to implement your own custom renderer. We provide 1st-class support for these renderers:
|
|
|
+//!
|
|
|
+//! - dioxus-desktop (via WebView)
|
|
|
+//! - dioxus-web (via WebSys)
|
|
|
+//! - dioxus-ssr (via StringRenderer)
|
|
|
+//! - dioxus-liveview (SSR + StringRenderer)
|
|
|
+//!
|
|
|
+//! In the main `Dioxus` crate, these are all accessible through configuration flags.
|
|
|
+//!
|
|
|
+//! ## Rendering to the Web
|
|
|
+//!
|
|
|
+//! Most dioxus apps will be initialized in roughly the same way. The `launch` method in `web` will immediately start a
|
|
|
+//! VirtualDOM and await it using `wasm_bindgen_futures`.
|
|
|
+//!
|
|
|
+//! VirtualDOM from
|
|
|
+//! a component root and immediately awaits it
|
|
|
+//!
|
|
|
+//!
|
|
|
+//! ```
|
|
|
+//! use dioxus::prelude::*;
|
|
|
+//! fn main() {
|
|
|
+//! wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
|
|
+//! console_error_panic_hook::set_once();
|
|
|
+//!
|
|
|
+//! diouxs::web::launch(Example);
|
|
|
+//! }
|
|
|
+//!
|
|
|
+//! static Example: FC<()> = |ctx| {
|
|
|
+//! ctx.render(rsx! {
|
|
|
+//! div { "Hello World!" }
|
|
|
+//! })
|
|
|
+//! };
|
|
|
+//! ```
|
|
|
+
|
|
|
+// Just a heads-up, the core functionality of dioxus rests in Dioxus-Core. This crate just wraps a bunch of utilities
|
|
|
+// together and exports their namespaces to something predicatble.
|
|
|
+#[cfg(feature = "core")]
|
|
|
+pub mod core {
|
|
|
+ //! Core functionality that includes the VirtualDOM, diffing, and Context APIs
|
|
|
+
|
|
|
+ // Re-export core completely
|
|
|
+ pub use dioxus_core::*;
|
|
|
+}
|
|
|
+pub mod prelude {
|
|
|
+ //! A glob import that includes helper types like FC, rsx!, html!, and required traits
|
|
|
+ pub use dioxus_core::prelude::*;
|
|
|
+ pub use dioxus_core_macro::fc;
|
|
|
+}
|
|
|
+
|
|
|
+#[cfg(feature = "web")]
|
|
|
+pub mod web {
|
|
|
+ //! A web-sys based renderer for building fast and interactive web applications
|
|
|
+}
|
|
|
+#[cfg(feature = "ssr")]
|
|
|
+pub mod ssr {
|
|
|
+ //! A dedicated renderer for writing a Dioxus VirtualDOM to a string
|
|
|
+}
|
|
|
+#[cfg(feature = "ssr")]
|
|
|
+pub mod hooks {
|
|
|
+ //! Useful hooks like use_state, use_ref
|
|
|
+}
|
|
|
+#[cfg(feature = "ssr")]
|
|
|
+pub mod router {
|
|
|
+ //! A cross-platform router implementation
|
|
|
+}
|
|
|
+#[cfg(feature = "ssr")]
|
|
|
+pub mod testing {
|
|
|
+ //! Tools to make it easier to write tests for Dioxus components
|
|
|
+}
|
|
|
+#[cfg(feature = "atoms")]
|
|
|
+pub mod atoms {}
|
|
|
+#[cfg(feature = "desktop")]
|
|
|
+pub mod desktop {
|
|
|
+ //! A webview based renderer for building desktop applications with Dioxus
|
|
|
+}
|