lib.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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. //!
  8. //! # Resources
  9. //!
  10. //! This overview provides a brief introduction to Dioxus. For a more in-depth guide, make sure to check out:
  11. //! - [Getting Started](https://dioxuslabs.com/getting-started)
  12. //! - [Book](https://dioxuslabs.com/book)
  13. //! - [Reference](https://dioxuslabs.com/reference)
  14. //! - [Community Examples](https://github.com/DioxusLabs/community-examples)
  15. //!
  16. //! # Overview and Goals
  17. //!
  18. //! Dioxus makes it easy to quickly build complex user interfaces with Rust. Any Dioxus app can run in the web browser,
  19. //! as a desktop app, as a mobile app, or anywhere else provided you build the right renderer.
  20. //!
  21. //! Dioxus is heavily inspired by React, supporting many of the same concepts:
  22. //!
  23. //! - Hooks for state
  24. //! - VirtualDom & diffing
  25. //! - Concurrency, fibers, and asynchronous rendering
  26. //! - JSX-like templating syntax
  27. //!
  28. //! If you know React, then you know Dioxus.
  29. //!
  30. //! Dioxus is *substantially* more performant than many of the other Rust UI libraries (Yew/Percy) and is *significantly* more performant
  31. //! than React - roughly competitve with InfernoJS.
  32. //!
  33. //! Remember: Dioxus is a library for declaring interactive user interfaces - it is not a dedicated renderer. Most 1st party renderers for Dioxus currently only support web technologies.
  34. //!
  35. //! ## Brief Overview
  36. //!
  37. //! All Dioxus apps are built by composing functions that take in a `Scope` which is generic over some `Properties` and return an `Element`.
  38. //! A `Scope` holds relevant state data for the the currently-rendered component.
  39. //!
  40. //! To launch an app, we use the `launch` method for the specific renderer we want to use. In the launch function, we pass the app's `Component`.
  41. //!
  42. //! ```rust, ignore
  43. //! use dioxus::prelude::*;
  44. //!
  45. //! fn main() {
  46. //! dioxus::desktop::launch(app);
  47. //! }
  48. //!
  49. //! fn app(cx: Scope) -> Element {
  50. //! cx.render(rsx!("hello world!"))
  51. //! }
  52. //! ```
  53. //!
  54. //! ## Elements & your first component
  55. //!
  56. //! To assemble UI trees with Dioxus, you need to use the `render` function on
  57. //! something called `LazyNodes`. To produce `LazyNodes`, you can use the `rsx!`
  58. //! macro or the NodeFactory API. For the most part, you want to use the `rsx!`
  59. //! macro.
  60. //!
  61. //! Any element in `rsx!` can have attributes, listeners, and children. For
  62. //! consistency, we force all attributes and listeners to be listed *before*
  63. //! children.
  64. //!
  65. //! ```rust, ignore
  66. //! let value = "123";
  67. //!
  68. //! rsx!(
  69. //! div {
  70. //! class: "my-class {value}", // <--- attribute
  71. //! onclick: move |_| log::info!("clicked!"), // <--- listener
  72. //! h1 { "hello world" }, // <--- child
  73. //! }
  74. //! )
  75. //! ```
  76. //!
  77. //! The `rsx!` macro accepts attributes in "struct form" and will parse the rest
  78. //! of the body as child elements and rust expressions. Any rust expression that
  79. //! implements `IntoIterator<Item = impl IntoVNode>` will be parsed as a child.
  80. //!
  81. //! ```rust, ignore
  82. //! rsx!(
  83. //! div {
  84. //! (0..10).map(|_| rsx!(span { "hello world" }))
  85. //! }
  86. //! )
  87. //!
  88. //! ```
  89. //!
  90. //! Used within components, the `rsx!` macro must be rendered into an `Element` with
  91. //! the `render` function on Scope.
  92. //!
  93. //! If we want to omit the boilerplate of `cx.render`, we can simply pass in
  94. //! `cx` as the first argument of rsx. This is sometimes useful when we need to
  95. //! render nodes in match statements.
  96. //!
  97. //! ```rust, ignore
  98. //! fn example(cx: Scope) -> Element {
  99. //!
  100. //! // both of these are equivalent
  101. //! cx.render(rsx!("hello world"))
  102. //!
  103. //! rsx!(cx, "hello world!")
  104. //! }
  105. //! ```
  106. //!
  107. //! Putting everything together, we can write a simple component that renders a list of
  108. //! elements:
  109. //!
  110. //! ```rust, ignore
  111. //! fn app(cx: Scope) -> Element {
  112. //! let name = "dave";
  113. //! cx.render(rsx!(
  114. //! h1 { "Hello, {name}!" }
  115. //! div {
  116. //! class: "my-class",
  117. //! id: "my-id",
  118. //!
  119. //! (0..5).map(|i| rsx!(
  120. //! div { key: "{i}"
  121. //! "FizzBuzz: {i}"
  122. //! }
  123. //! ))
  124. //!
  125. //! }
  126. //! ))
  127. //! }
  128. //! ```
  129. //!
  130. //! ## Components
  131. //!
  132. //! We can compose these function components to build a complex app. Each new
  133. //! component we design must take some Properties. For components with no explicit
  134. //! properties, we can use the `()` type or simply omit the type altogether.
  135. //!
  136. //! In Dioxus, all properties are memoized by default!
  137. //!
  138. //! ```rust, ignore
  139. //! fn App(cx: Scope) -> Element {
  140. //! cx.render(rsx!(
  141. //! Header {
  142. //! title: "My App",
  143. //! color: "red",
  144. //! }
  145. //! ))
  146. //! }
  147. //! ```
  148. //!
  149. //! Our `Header` component takes a `title` and a `color` property, which we
  150. //! declare on an explicit `HeaderProps` struct.
  151. //!
  152. //! ```rust, ignore
  153. //! // The `Props` derive macro lets us add additional functionality to how props are interpreted.
  154. //! #[derive(Props, PartialEq)]
  155. //! struct HeaderProps {
  156. //! title: String,
  157. //! color: String,
  158. //! }
  159. //!
  160. //! fn Header(cx: Scope<HeaderProps>) -> Element {
  161. //! cx.render(rsx!(
  162. //! div {
  163. //! background_color: "{cx.props.color}"
  164. //! h1 { "{cx.props.title}" }
  165. //! }
  166. //! ))
  167. //! }
  168. //! ```
  169. //!
  170. //! Components may use the `inline_props` macro to completely inline the props
  171. //! definition into the function arguments.
  172. //!
  173. //! ```rust, ignore
  174. //! #[inline_props]
  175. //! fn Header(cx: Scope, title: String, color: String) -> Element {
  176. //! cx.render(rsx!(
  177. //! div {
  178. //! background_color: "{color}"
  179. //! h1 { "{title}" }
  180. //! }
  181. //! ))
  182. //! }
  183. //! ```
  184. //!
  185. //! Components may also borrow data from their parent component. We just need to
  186. //! attach some lifetimes to the props struct.
  187. //! > Note: we don't need to derive `PartialEq` for borrowed props since they cannot be memoized.
  188. //!
  189. //! ```rust, ignore
  190. //! #[derive(Props)]
  191. //! struct HeaderProps<'a> {
  192. //! title: &'a str,
  193. //! color: &'a str,
  194. //! }
  195. //!
  196. //! fn Header<'a>(cx: Scope<'a, HeaderProps<'a>>) -> Element {
  197. //! cx.render(rsx!(
  198. //! div {
  199. //! background_color: "{cx.props.color}"
  200. //! h1 { "{cx.props.title}" }
  201. //! }
  202. //! ))
  203. //! }
  204. //! ```
  205. //!
  206. //! Components that begin with an uppercase letter may be called with
  207. //! the traditional (for React) curly-brace syntax like so:
  208. //!
  209. //! ```rust, ignore
  210. //! rsx!(
  211. //! Header { title: "My App" }
  212. //! )
  213. //! ```
  214. //!
  215. //! Alternatively, if your components begin with a lowercase letter, you can use
  216. //! the function call syntax:
  217. //!
  218. //! ```rust, ignore
  219. //! rsx!(
  220. //! header( title: "My App" )
  221. //! )
  222. //! ```
  223. //!
  224. //! ## Hooks
  225. //!
  226. //! While components are reusable forms of UI elements, hooks are reusable forms
  227. //! of logic. Hooks provide us a way of retrieving state from the `Scope` and using
  228. //! it to render UI elements.
  229. //!
  230. //! By convention, all hooks are functions that should start with `use_`. We can
  231. //! use hooks to define state and modify it from within listeners.
  232. //!
  233. //! ```rust, ignore
  234. //! fn app(cx: Scope) -> Element {
  235. //! let name = use_state(&cx, || "world");
  236. //!
  237. //! rsx!(cx, "hello {name}!")
  238. //! }
  239. //! ```
  240. //!
  241. //! Hooks are sensitive to how they are used. To use hooks, you must abide by the
  242. //! ["rules of hooks" (borrowed from react)](https://reactjs.org/docs/hooks-rules.html):
  243. //! - Functions with "use_" should not be called in callbacks
  244. //! - Functions with "use_" should not be called out of order
  245. //! - Functions with "use_" should not be called in loops or conditionals
  246. //!
  247. //! In a sense, hooks let us add a field of state to our component without declaring
  248. //! an explicit state struct. However, this means we need to "load" the struct in the right
  249. //! order. If that order is wrong, then the hook will pick the wrong state and panic.
  250. //!
  251. //! Most hooks you'll write are simply composition of other hooks:
  252. //!
  253. //! ```rust, ignore
  254. //! fn use_username(cx: &ScopeState, id: Uuid) -> bool {
  255. //! let users = use_context::<Users>(cx);
  256. //! users.get(&id).map(|user| user.logged_in).ok_or(false)
  257. //! }
  258. //! ```
  259. //!
  260. //! To create entirely new foundational hooks, we can use the `use_hook` method on `ScopeState`.
  261. //!
  262. //! ```rust, ignore
  263. //! fn use_mut_string(cx: &ScopeState) -> &mut String {
  264. //! cx.use_hook(|_| "Hello".to_string())
  265. //! }
  266. //! ```
  267. //!
  268. //! If you want to extend Dioxus with some new functionality, you'll probably want to implement a new hook from scratch.
  269. //!
  270. //! ## Putting it all together
  271. //!
  272. //! Using components, templates, and hooks, we can build a simple app.
  273. //!
  274. //! ```rust, ignore
  275. //! use dioxus::prelude::*;
  276. //!
  277. //! fn main() {
  278. //! dioxus::desktop::launch(App);
  279. //! }
  280. //!
  281. //! fn App(cx: Scope) -> Element {
  282. //! let mut count = use_state(&cx, || 0);
  283. //!
  284. //! cx.render(rsx!(
  285. //! div { "Count: {count}" }
  286. //! button { onclick: move |_| count += 1, "Increment" }
  287. //! button { onclick: move |_| count -= 1, "Decrement" }
  288. //! ))
  289. //! }
  290. //! ```
  291. //!
  292. //! ## Features
  293. //!
  294. //! This overview doesn't cover everything. Make sure to check out the tutorial and reference guide on the official
  295. //! website for more details.
  296. //!
  297. //! Beyond this overview, Dioxus supports:
  298. //! - Server-side rendering
  299. //! - Concurrent rendering (with async support)
  300. //! - Web/Desktop/Mobile support
  301. //! - Pre-rendering and rehydration
  302. //! - Fragments, Portals, and Suspense
  303. //! - Inline-styles
  304. //! - Custom event handlers
  305. //! - Custom elements
  306. //! - Basic fine-grained reactivity (IE SolidJS/Svelte)
  307. //! - and more!
  308. //!
  309. //! Good luck!
  310. //!
  311. //! ## Inspiration, Resources, Alternatives and Credits
  312. //!
  313. //! Dioxus is inspired by:
  314. //! - React: for its hooks, concurrency, suspense
  315. //! - Dodrio: for its research in bump allocation, double buffering, and diffing architecture
  316. //!
  317. //! Alternatives to Dioxus include:
  318. //! - Yew: supports function components and web, but no SSR, borrowed data, or bump allocation. Rather slow at times.
  319. //! - Percy: supports function components, web, ssr, but lacks state management
  320. //! - Sycamore: supports function components, web, ssr, but closer to SolidJS than React
  321. //! - MoonZoom/Seed: opinionated frameworks based on the Elm model (message, update) - no hooks
  322. //!
  323. //! We've put a lot of work into making Dioxus ergonomic and *familiar*.
  324. //! Our target audience is TypeSrcipt developers looking to switch to Rust for the web - so we need to be comparabale to React.
  325. pub use dioxus_core as core;
  326. #[cfg(feature = "hooks")]
  327. pub use dioxus_hooks as hooks;
  328. #[cfg(feature = "router")]
  329. pub use dioxus_router as router;
  330. #[cfg(feature = "ssr")]
  331. pub use dioxus_ssr as ssr;
  332. #[cfg(feature = "web")]
  333. pub use dioxus_web as web;
  334. #[cfg(feature = "desktop")]
  335. pub use dioxus_desktop as desktop;
  336. #[cfg(feature = "fermi")]
  337. pub use fermi;
  338. // #[cfg(feature = "mobile")]
  339. // pub use dioxus_mobile as mobile;
  340. pub mod events {
  341. #[cfg(feature = "html")]
  342. pub use dioxus_html::{on::*, KeyCode};
  343. }
  344. pub mod prelude {
  345. pub use dioxus_core::prelude::*;
  346. pub use dioxus_core_macro::{format_args_f, inline_props, rsx, Props, Routable};
  347. pub use dioxus_elements::{GlobalAttributes, SvgAttributes};
  348. pub use dioxus_hooks::*;
  349. pub use dioxus_html as dioxus_elements;
  350. }