Remove some old docs, cleanup some readmes

This commit is contained in:
Jonathan Kelley committed 2024-03-27 17:28:30 -07:00
1 parent a1c03a461d
commit 537f064001
12 files changed
+81 -203

No files matched your search

+10 -15
View File
@@ -196,24 +196,19 @@ pub fn schedule_update_any() -> Arc<dyn Fn(ScopeId) + Send + Sync> {
/// ///
/// fn child_component() -> Element { /// fn child_component() -> Element {
/// let original_scroll_position = use_signal(|| 0.0); /// let original_scroll_position = use_signal(|| 0.0);
/// use_effect((), move |_| { ///
/// to_owned![original_scroll_position]; /// use_effect(move |_| async move {
/// async move { /// let window = web_sys::window().unwrap();
/// let window = web_sys::window().unwrap(); /// let document = window.document().unwrap();
/// let document = window.document().unwrap(); /// let element = document.get_element_by_id("my_element").unwrap();
/// let element = document.get_element_by_id("my_element").unwrap(); /// element.scroll_into_view();
/// element.scroll_into_view(); /// original_scroll_position.set(window.scroll_y().unwrap());
/// original_scroll_position.set(window.scroll_y().unwrap());
/// }
/// }); /// });
/// ///
/// use_drop({ /// use_drop(move || {
/// to_owned![original_scroll_position];
/// /// restore scroll to the top of the page /// /// restore scroll to the top of the page
/// move || { /// let window = web_sys::window().unwrap();
/// let window = web_sys::window().unwrap(); /// window.scroll_with_x_and_y(*original_scroll_position.current(), 0.0);
/// window.scroll_with_x_and_y(*original_scroll_position.current(), 0.0);
/// }
/// }); /// });
/// ///
/// rsx!{ /// rsx!{
-27
View File
@@ -46,33 +46,6 @@ pub(crate) mod innerlude {
pub type Element = Option<VNode>; pub type Element = Option<VNode>;
/// A [`Component`] is a function that takes [`Properties`] and returns an [`Element`]. /// A [`Component`] is a function that takes [`Properties`] and returns an [`Element`].
///
/// Components can be used in other components with two syntax options:
/// - lowercase as a function call with named arguments (rust style)
/// - uppercase as an element (react style)
///
/// ## Rust-Style
///
/// ```rust, ignore
/// fn example(cx: Props) -> Element {
/// // ...
/// }
///
/// rsx!(
/// example()
/// )
/// ```
///
/// ## React-Style
/// ```rust, ignore
/// fn Example(cx: Props) -> Element {
/// // ...
/// }
///
/// rsx!(
/// Example {}
/// )
/// ```
pub type Component<P = ()> = fn(P) -> Element; pub type Component<P = ()> = fn(P) -> Element;
} }
+1 -5
View File
@@ -20,11 +20,7 @@ pub type TemplateId = &'static str;
/// The actual state of the component's most recent computation /// The actual state of the component's most recent computation
/// ///
/// Because Dioxus accepts components in the form of `async fn() -> Result<VNode>`, we need to support both /// If the component returned early (e.g. `return None`), this will be Aborted(None)
/// sync and async versions.
///
/// Dioxus will do its best to immediately resolve any async components into a regular Element, but as an implementor
/// you might need to handle the case where there's no node immediately ready.
pub enum RenderReturn { pub enum RenderReturn {
/// A currently-available element /// A currently-available element
Ready(VNode), Ready(VNode),
+2
View File
@@ -5,6 +5,8 @@
</p> </p>
</div> </div>
> This crate implements dioxus-lib which is a renderer-free version of Dioxus. This crate is intended to be used by library authors who need a stable core verison of dioxus withuot pulling in renderer-related dependencies on accident.
# Resources # Resources
This overview provides a brief introduction to Dioxus. For a more in-depth guide, make sure to check out: This overview provides a brief introduction to Dioxus. For a more in-depth guide, make sure to check out:
+34 -92
View File
@@ -34,11 +34,11 @@ Remember: Dioxus is a library for declaring interactive user interfaces—it is
## Brief Overview ## Brief Overview
All Dioxus apps are built by composing functions that return an `Element`. All Dioxus apps are built by composing functions that return an `Element`.
To launch an app, we use the `launch` method and use features in ``Cargo.toml`` to specify which renderer we want to use. In the launch function, we pass the app's root `Component`. To launch an app, we use the `launch` method and use features in ``Cargo.toml`` to specify which renderer we want to use. In the launch function, we pass the app's root `Component`.
```rust, ignore ```rust
use dioxus::prelude::*; use dioxus::prelude::*;
fn main() { fn main() {
@@ -49,7 +49,7 @@ fn main() {
// It's not required, but highly recommended. For example, UpperCamelCase components will not generate a warning. // It's not required, but highly recommended. For example, UpperCamelCase components will not generate a warning.
#[component] #[component]
fn App() -> Element { fn App() -> Element {
rsx!("hello world!") rsx! { "hello world!" }
} }
``` ```
@@ -67,25 +67,25 @@ children.
```rust, ignore ```rust, ignore
let value = "123"; let value = "123";
rsx!( rsx! {
div { div {
class: "my-class {value}", // <--- attribute class: "my-class {value}", // <--- attribute
onclick: move |_| info!("clicked!"), // <--- listener onclick: move |_| info!("clicked!"), // <--- listener
h1 { "hello world" }, // <--- child h1 { "hello world" }, // <--- child
} }
) }
``` ```
The `rsx!` macro accepts attributes in "struct form" and will parse the rest The `rsx!` macro accepts attributes in "struct form". Any rust expression contained within curly braces that implements `IntoIterator<Item = impl IntoVNode>` will be parsed as a child. We make two exceptions: both `for` loops and `if` statements are parsed where their body is parsed as a child.
of the body as child elements and rust expressions. Any rust expression that
implements `IntoIterator<Item = impl IntoVNode>` will be parsed as a child.
```rust, ignore ```rust, ignore
rsx!( rsx! {
div { div {
(0..10).map(|_| rsx!(span { "hello world" })) for _ in 0..10 {
span { "hello world" }
}
} }
) }
``` ```
The `rsx!` macro is what generates the `Element` that our components return. The `rsx!` macro is what generates the `Element` that our components return.
@@ -93,7 +93,7 @@ The `rsx!` macro is what generates the `Element` that our components return.
```rust, ignore ```rust, ignore
#[component] #[component]
fn Example() -> Element { fn Example() -> Element {
rsx!("hello world") rsx!{ "hello world" }
} }
``` ```
@@ -104,20 +104,14 @@ elements:
#[component] #[component]
fn App() -> Element { fn App() -> Element {
let name = "dave"; let name = "dave";
rsx!( rsx! {
h1 { "Hello, {name}!" } h1 { "Hello, {name}!" }
div { div { class: "my-class", id: "my-id",
class: "my-class", for i in 0..5 {
id: "my-id", div { "FizzBuzz: {i}" }
}
(0..5).map(|i| rsx!(
div { key: "{i}"
"FizzBuzz: {i}"
}
))
} }
) }
} }
``` ```
@@ -125,19 +119,19 @@ fn App() -> Element {
We can compose these function components to build a complex app. Each new We can compose these function components to build a complex app. Each new
component we design must take some Properties. For components with no explicit component we design must take some Properties. For components with no explicit
properties, we can use the `()` type or simply omit the type altogether. properties we can omit the type altogether.
In Dioxus, all properties are memoized by default! In Dioxus, all properties are memoized by default, and this implement both Clone and PartialEq. For props you can't clone, simply wrap the fields in a ReadOnlySignal and Dioxus will handle the wrapping for you.
```rust, ignore ```rust, ignore
#[component] #[component]
fn App() -> Element { fn App() -> Element {
rsx!( rsx! {
Header { Header {
title: "My App", title: "My App",
color: "red", color: "red",
} }
) }
} }
``` ```
@@ -154,12 +148,12 @@ struct HeaderProps {
#[component] #[component]
fn Header(props: HeaderProps) -> Element { fn Header(props: HeaderProps) -> Element {
rsx!( rsx! {
div { div {
background_color: "{props.color}" background_color: "{props.color}"
h1 { "{props.title}" } h1 { "{props.title}" }
} }
) }
} }
``` ```
@@ -169,35 +163,12 @@ struct from function arguments:
```rust, ignore ```rust, ignore
#[component] #[component]
fn Header(title: String, color: String) -> Element { fn Header(title: String, color: String) -> Element {
rsx!( rsx! {
div { div {
background_color: "{color}" background_color: "{color}"
h1 { "{title}" } h1 { "{title}" }
} }
) }
}
```
Components may also borrow data from their parent component. We just need to
attach some lifetimes to the props struct.
> Note: we don't need to derive `PartialEq` for borrowed props since they cannot be memoized.
```rust, ignore
#[derive(Props)]
struct HeaderProps<'a> {
title: &'a str,
color: &'a str,
}
#[component]
fn Header<'a>(props: HeaderProps<'a>) -> Element {
rsx!(
div {
background_color: "{props.color}"
h1 { "{props.title}" }
}
)
} }
``` ```
@@ -205,23 +176,11 @@ Components that begin with an uppercase letter may be called with
the traditional (for React) curly-brace syntax like so: the traditional (for React) curly-brace syntax like so:
```rust, ignore ```rust, ignore
rsx!( rsx! {
Header { title: "My App" } Header { title: "My App" }
) }
``` ```
Alternatively, if your components begin with a lowercase letter, you can use
the function call syntax:
```rust, ignore
rsx!(
header( title: "My App" )
)
```
However, the convention is to use UpperCamelCase. The `#[component]` attribute will enforce this,
but you can turn it off if you wish.
## Hooks ## Hooks
While components are reusable forms of UI elements, hooks are reusable forms While components are reusable forms of UI elements, hooks are reusable forms
@@ -236,7 +195,7 @@ use hooks to define the state and modify it from within listeners.
fn App() -> Element { fn App() -> Element {
let name = use_signal(|| "world"); let name = use_signal(|| "world");
rsx!("hello {name}!") rsx! { "hello {name}!" }
} }
``` ```
@@ -263,7 +222,7 @@ fn use_username(d: Uuid) -> bool {
To create entirely new foundational hooks, we can use the `use_hook` method. To create entirely new foundational hooks, we can use the `use_hook` method.
```rust, ignore ```rust, ignore
fn use_mut_string() -> &mut String { fn use_mut_string() -> String {
use_hook(|_| "Hello".to_string()) use_hook(|_| "Hello".to_string())
} }
``` ```
@@ -283,12 +242,12 @@ fn main() {
#[component] #[component]
fn App() -> Element { fn App() -> Element {
let count = use_signal(|| 0); let mut count = use_signal(|| 0);
rsx!( rsx!(
div { "Count: {count}" } div { "Count: {count}" }
button { onclick: move |_| count.set(count + 1), "Increment" } button { onclick: move |_| count += 1, "Increment" }
button { onclick: move |_| count.set(count - 1), "Decrement" } button { onclick: move |_| count -= 1, "Decrement" }
) )
} }
``` ```
@@ -311,21 +270,4 @@ Beyond this overview, Dioxus supports:
- Basic fine-grained reactivity (IE SolidJS/Svelte) - Basic fine-grained reactivity (IE SolidJS/Svelte)
- and more! - and more!
Good luck! Build cool things ✌️
## Inspiration, Resources, Alternatives, and Credits
Dioxus is inspired by:
- React: for its hooks, concurrency, suspense
- Dodrio: for its research in bump allocation, double buffering, and diffing architecture
Alternatives to Dioxus include:
- Yew: supports function components and web, but no SSR, borrowed data, or bump allocation. Rather slow at times.
- Percy: supports function components, web, ssr, but lacks state management
- Sycamore: supports function components, web, ssr, but is closer to SolidJS than React
- MoonZoom/Seed: opinionated frameworks based on the Elm model (message, update)—no hooks
We've put a lot of work into making Dioxus ergonomic and _familiar_.
Our target audience is TypeScript developers looking to switch to Rust for the web—so we need to be comparable to React.
@@ -76,13 +76,12 @@ fn main() {
} }
// //
fn app() -> Element { fn app() -> Element {
let user_name = use_signal(|| "?".to_string()); let mut user_name = use_signal(|| "?".to_string());
let permissions = use_signal(|| "?".to_string()); let mut permissions = use_signal(|| "?".to_string());
rsx! { rsx! {
div { div {
button { button { onclick: move |_| {
onclick: move |_| {
async move { async move {
login().await.unwrap(); login().await.unwrap();
} }
@@ -92,12 +91,9 @@ fn app() -> Element {
} }
div { div {
button { button {
onclick: move |_| { onclick: move |_| async move {
to_owned![user_name]; if let Ok(data) = get_user_name().await {
async move { user_name.set(data);
if let Ok(data) = get_user_name().await {
user_name.set(data);
}
} }
}, },
"Get User Name" "Get User Name"
@@ -106,12 +102,9 @@ fn app() -> Element {
} }
div { div {
button { button {
onclick: move |_| { onclick: move |_| async move {
to_owned![permissions]; if let Ok(data) = get_permissions().await {
async move { permissions.set(data);
if let Ok(data) = get_permissions().await {
permissions.set(data);
}
} }
}, },
"Get Permissions" "Get Permissions"
@@ -3,21 +3,18 @@ use dioxus::prelude::*;
pub fn app() -> Element { pub fn app() -> Element {
let mut count = use_signal(|| 0); let mut count = use_signal(|| 0);
let text = use_signal(|| "...".to_string()); let mut text = use_signal(|| "...".to_string());
rsx! { rsx! {
h1 { "High-Five counter: {count}" } h1 { "High-Five counter: {count}" }
button { onclick: move |_| count += 1, "Up high!" } button { onclick: move |_| count += 1, "Up high!" }
button { onclick: move |_| count -= 1, "Down low!" } button { onclick: move |_| count -= 1, "Down low!" }
button { button {
onclick: move |_| { onclick: move |_| async move {
to_owned![text]; if let Ok(data) = get_server_data().await {
async move { println!("Client received: {}", data);
if let Ok(data) = get_server_data().await { text.set(data.clone());
println!("Client received: {}", data); post_server_data(data).await.unwrap();
text.set(data.clone());
post_server_data(data).await.unwrap();
}
} }
}, },
"Run a server function" "Run a server function"
@@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
fn app() -> Element { fn app() -> Element {
let mut count = use_signal(|| 0); let mut count = use_signal(|| 0);
let text = use_signal(|| "...".to_string()); let mut text = use_signal(|| "...".to_string());
let server_future = use_server_future(get_server_data)?; let server_future = use_server_future(get_server_data)?;
rsx! { rsx! {
@@ -18,14 +18,11 @@ fn app() -> Element {
button { onclick: move |_| count += 1, "Up high!" } button { onclick: move |_| count += 1, "Up high!" }
button { onclick: move |_| count -= 1, "Down low!" } button { onclick: move |_| count -= 1, "Down low!" }
button { button {
onclick: move |_| { onclick: move |_| async move {
to_owned![text]; if let Ok(data) = get_server_data().await {
async move { println!("Client received: {}", data);
if let Ok(data) = get_server_data().await { text.set(data.clone());
println!("Client received: {}", data); post_server_data(data).await.unwrap();
text.set(data.clone());
post_server_data(data).await.unwrap();
}
} }
}, },
"Run a server function!" "Run a server function!"
@@ -15,9 +15,7 @@ fn main() {
} }
fn app() -> Element { fn app() -> Element {
rsx! { rsx! { Router::<Route> {} }
Router::<Route> {}
}
} }
#[derive(Clone, Routable, Debug, PartialEq, serde::Serialize, serde::Deserialize)] #[derive(Clone, Routable, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
@@ -50,28 +48,20 @@ fn Blog(id: i32) -> Element {
#[component] #[component]
fn Home() -> Element { fn Home() -> Element {
let mut count = use_signal(|| 0); let mut count = use_signal(|| 0);
let text = use_signal(|| "...".to_string()); let mut text = use_signal(|| "...".to_string());
rsx! { rsx! {
Link { Link { to: Route::Blog { id: count() }, "Go to blog" }
to: Route::Blog {
id: count()
},
"Go to blog"
}
div { div {
h1 { "High-Five counter: {count}" } h1 { "High-Five counter: {count}" }
button { onclick: move |_| count += 1, "Up high!" } button { onclick: move |_| count += 1, "Up high!" }
button { onclick: move |_| count -= 1, "Down low!" } button { onclick: move |_| count -= 1, "Down low!" }
button { button {
onclick: move |_| { onclick: move |_| async move {
to_owned![text]; if let Ok(data) = get_server_data().await {
async move { println!("Client received: {}", data);
if let Ok(data) = get_server_data().await { text.set(data.clone());
println!("Client received: {}", data); post_server_data(data).await.unwrap();
text.set(data.clone());
post_server_data(data).await.unwrap();
}
} }
}, },
"Run server function!" "Run server function!"
+4 -7
View File
@@ -30,16 +30,13 @@
//! } //! }
//! //!
//! fn app() -> Element { //! fn app() -> Element {
//! let text = use_signal(|| "...".to_string()); //! let mut text = use_signal(|| "...".to_string());
//! //!
//! rsx! { //! rsx! {
//! button { //! button {
//! onclick: move |_| { //! onclick: move |_| async move {
//! to_owned![text]; //! if let Ok(data) = get_server_data().await {
//! async move { //! text.set(data);
//! if let Ok(data) = get_server_data().await {
//! text.set(data);
//! }
//! } //! }
//! }, //! },
//! "Run a server function" //! "Run a server function"
-4
View File
@@ -32,10 +32,6 @@
Unlike React, none of these hooks are foundational since they all build off the primitive `use_hook`. Unlike React, none of these hooks are foundational since they all build off the primitive `use_hook`.
This crate also provides a helpful macro to get around some Rust lifetime management issues in async:
- `to_owned![]`
## Contributing ## Contributing
- Report issues on our [issue tracker](https://github.com/dioxuslabs/dioxus/issues). - Report issues on our [issue tracker](https://github.com/dioxuslabs/dioxus/issues).
+1 -1
View File
@@ -3,7 +3,7 @@
#![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")] #![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")]
#[macro_export] #[macro_export]
/// A helper macro for using hooks and properties in async environments. /// A helper macro for cloning multiple values at once
/// ///
/// # Usage /// # Usage
/// ///