lib.rs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. //! <div align="center">
  2. //! <h1>🌗🚀 📦 Dioxus</h1>
  3. //! <p>
  4. //! <strong>A concurrent, functional, virtual DOM for Rust</strong>
  5. //! </p>
  6. //! </div>
  7. //! Dioxus: a concurrent, functional, reactive virtual dom for any renderer in Rust.
  8. //!
  9. //! This crate aims to maintain a hook-based, renderer-agnostic framework for cross-platform UI development.
  10. //!
  11. //! ## Overview and Goals
  12. //! Dioxus' ultimate goal is to save you from writing new code when bringing your application to new platforms. We forsee
  13. //! a future where WebApps, Mobile Apps, Desktop Apps, and even AR apps can be written in the same language, ecosystem,
  14. //! and leverage the same platform-agnostic libraries.
  15. //!
  16. //! In this aim we chose to use a variety of techniques:
  17. //! - We use a VirtualDOM to abstract the true renderer from application logic.
  18. //! - We use functions as components to limit the API churn for greater stability.
  19. //! - We use hooks as state to allow reusable logic across the whole ecosystem.
  20. //! - We support an extensible and compile-time safe DSL for building interfaces.
  21. //!
  22. //! Our guiding stars (in order of priority):
  23. //! - Ergonomics
  24. //! - Reusability
  25. //! - Speed and memory efficiency
  26. //! - Safety
  27. //!
  28. //! ## Components
  29. //! The base unit of Dioxus is the `component`. Components can be easily created from just a function - no traits or
  30. //! proc macros required:
  31. //!
  32. //! ```
  33. //! use dioxus::prelude::*;
  34. //!
  35. //! fn Example(ctx: Context<()>) -> VNode {
  36. //! html! { <div> "Hello, world!" </div> }
  37. //! }
  38. //! ```
  39. //! Components need to take a "Context" parameter which is generic over some properties. This defines how the component can be used
  40. //! and what properties can be used to specify it in the VNode output. Components without properties may be generic over
  41. //! `()`, and components with properties must declare their properties as a struct:
  42. //!
  43. //! ```
  44. //! #[derive(Props)]
  45. //! struct Props { name: String }
  46. //!
  47. //! fn Example(ctx: Context<Props>) -> VNode {
  48. //! html! { <div> "Hello {ctx.props.name}!" </div> }
  49. //! }
  50. //! ```
  51. //!
  52. //! Props that are valid for the `'static` lifetime automatically get memoized by Diouxs. This means the component won't
  53. //! re-render if its Props didn't change. However, Props that borrow data from their parent cannot be safely memoized, and
  54. //! will always re-render if their parent changes. To borrow data from a parent, your component needs to add explicit lifetimes,
  55. //! otherwise Rust will get confused about whether data is borrowed from either Props or Context. Since Dioxus manages
  56. //! these lifetimes internally, Context and your Props must share the same lifetime:
  57. //!
  58. //! ```
  59. //! #[derive(Props)]
  60. //! struct Props<'a> { name: &'a str }
  61. //!
  62. //! fn Example<'a>(ctx: Context<'a, Props<'a>>) -> VNode {
  63. //! html! { <div> "Hello {ctx.props.name}!" </div> }
  64. //! }
  65. //! ```
  66. //!
  67. //!
  68. //!
  69. //! The lifetimes might look a little messy, but are crucially important for Dioxus's efficiency and overall ergonimics.
  70. //! Components can also be crafted as static closures, enabling type inference without all the type signature noise. However,
  71. //! closure-style components cannot work with borrowed data, due to limitations in Rust's lifetime system.
  72. //!
  73. //! ```
  74. //! #[derive(Props)]
  75. //! struct Props { name: String }
  76. //!
  77. //! static Example: FC<Props> = |ctx| {
  78. //! html! { <div> "Hello {ctx.props.name}!" </div> }
  79. //! }
  80. //! ```
  81. //!
  82. //! To use custom properties for components, you'll need to derive the `Props` trait for your properties. This trait
  83. //! exposes a compile-time correct builder pattern (similar to typed-builder) that can be used in the `rsx!` and `html!`
  84. //! macros to build components. Component props may have default fields notated by the `Default` attribute:
  85. //!
  86. //! ```
  87. //! #[derive(Props)]
  88. //! struct Props {
  89. //! name: String
  90. //!
  91. //! #[props(default = false)]
  92. //! checked: bool,
  93. //!
  94. //! #[props(default, setter(strip_option, into))]
  95. //! title: Option<String>
  96. //! }
  97. //! ```
  98. //!
  99. //! These flags roughly follow that of typed-builder, though tweaked to support the `Props` usecase.
  100. //!
  101. //! ## Hooks and State
  102. //! Dioxus uses hooks for state management. Hooks are a form of state persisted between calls of the function component.
  103. //!
  104. //! ```
  105. //! static Example: FC<()> = |ctx| {
  106. //! let (val, set_val) = use_state(&ctx, || 0);
  107. //! ctx.render(rsx!(
  108. //! button { onclick: move |_| set_val(val + 1) }
  109. //! ))
  110. //! }
  111. //! ````
  112. //!
  113. //! Instead of using a single struct to represent a component and its state, hooks use the "use_hook" building block
  114. //! which allows the persistence of data between function component renders. This primitive is exposed directly through
  115. //! the `Context` item:
  116. //! ```
  117. //! fn my_hook<'a>(ctx: &impl Scoped<'a>) -> &'a String {
  118. //! ctx.use_hook(
  119. //! // Initializer stores a value
  120. //! || String::new("stored_data"),
  121. //!
  122. //! // Runner returns the hook value every time the component is rendered
  123. //! |hook| &*hook,
  124. //!
  125. //! // Cleanup runs after the component is unmounted
  126. //! |hook| log::debug!("cleaning up hook with value {:#?}", hook)
  127. //! )
  128. //! }
  129. //! ```
  130. //! Under the hood, hooks store their data in a series of "memory cells". The first render defines the layout of these
  131. //! memory cells, and on each subsequent render, each `use_hook` call accesses its corresponding memory cell. If a hook
  132. //! accesses the wrong memory cell, `use_hook` will panic, and your app will crash. You can always use `try_use_hook` but
  133. //! these types of errors can be easily mitigated by following the rules of hooks:
  134. //!
  135. //! - Don’t call Hooks inside loops, conditions, or nested functions
  136. //! - Don't call hooks in changing order between renders
  137. //!
  138. //! Hooks provide a very powerful way to reuse stateful logic between components, simplify large complex components,
  139. //! and adopt more clear context subscription patterns to make components easier to read. The mechanics of hooks in Dioxus
  140. //! shares a great amount of similarity with React's hooks and there are many guides to hooks in React online.
  141. //!
  142. //! ## Supported Renderers
  143. //! Instead of being tightly coupled to a platform, browser, or toolkit, Dioxus implements a VirtualDOM object which
  144. //! can be consumed to draw the UI. The Dioxus VDOM is reactive and easily consumable by 3rd-party renderers via
  145. //! the `Patch` object. See [Implementing a Renderer](docs/8-custom-renderer.md) and the `StringRenderer` classes for information
  146. //! on how to implement your own custom renderer. We provide 1st-class support for these renderers:
  147. //!
  148. //! - dioxus-desktop (via WebView)
  149. //! - dioxus-web (via WebSys)
  150. //! - dioxus-ssr (via StringRenderer)
  151. //! - dioxus-liveview (SSR + StringRenderer)
  152. //!
  153. //! In the main `Dioxus` crate, these are all accessible through configuration flags.
  154. //!
  155. //! ## Rendering to the Web
  156. //!
  157. //! Most dioxus apps will be initialized in roughly the same way. The `launch` method in `web` will immediately start a
  158. //! VirtualDOM and await it using `wasm_bindgen_futures`.
  159. //!
  160. //! VirtualDOM from
  161. //! a component root and immediately awaits it
  162. //!
  163. //!
  164. //! ```
  165. //! use dioxus::prelude::*;
  166. //! fn main() {
  167. //! wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
  168. //! console_error_panic_hook::set_once();
  169. //!
  170. //! diouxs::web::launch(Example);
  171. //! }
  172. //!
  173. //! static Example: FC<()> = |ctx| {
  174. //! ctx.render(rsx! {
  175. //! div { "Hello World!" }
  176. //! })
  177. //! };
  178. //! ```
  179. pub mod prelude {
  180. //! A glob import that includes helper types like FC, rsx!, html!, and required traits
  181. pub use dioxus_core::prelude::*;
  182. pub use dioxus_core_macro::fc;
  183. }
  184. pub mod builder {
  185. // pub use dioxus_core::builder::*;
  186. }
  187. pub mod events {
  188. // pub use dioxus_core::events::*;
  189. }
  190. // Just a heads-up, the core functionality of dioxus rests in Dioxus-Core. This crate just wraps a bunch of utilities
  191. // together and exports their namespaces to something predicatble.
  192. #[cfg(feature = "core")]
  193. pub mod core {
  194. //! Core functionality that includes the VirtualDOM, diffing, and Context APIs
  195. // Re-export core completely
  196. pub use dioxus_core::*;
  197. }
  198. // Input elements work differently on different platforms.
  199. // This module helps abstract over Selects, TextInputs, TextAreas, Radios, etc for a cross-platform input experience
  200. pub mod inputs {
  201. //! Cross-platform abstractions over user inputs
  202. }
  203. #[cfg(feature = "web")]
  204. pub mod web {
  205. //! A web-sys based renderer for building fast and interactive web applications
  206. }
  207. #[cfg(feature = "ssr")]
  208. pub mod ssr {
  209. //! A dedicated renderer for writing a Dioxus VirtualDOM to a string
  210. }
  211. #[cfg(feature = "ssr")]
  212. pub mod hooks {
  213. //! Useful hooks like use_state, use_ref
  214. }
  215. #[cfg(feature = "ssr")]
  216. pub mod router {
  217. //! A cross-platform router implementation
  218. }
  219. #[cfg(feature = "ssr")]
  220. pub mod testing {
  221. //! Tools to make it easier to write tests for Dioxus components
  222. }
  223. #[cfg(feature = "atoms")]
  224. pub mod atoms {}
  225. // #[cfg(feature = "desktop")]
  226. pub mod webview {
  227. //! A webview based renderer for building desktop applications with Dioxus
  228. use dioxus_core::prelude::FC;
  229. pub fn launch<P>(f: FC<P>) {}
  230. }