mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-22 12:13:04 +00:00
Remove some old docs, cleanup some readmes
This commit is contained in:
parent
a1c03a461d
commit
537f064001
12 changed files with 81 additions and 203 deletions
|
@ -196,24 +196,19 @@ pub fn schedule_update_any() -> Arc<dyn Fn(ScopeId) + Send + Sync> {
|
|||
///
|
||||
/// fn child_component() -> Element {
|
||||
/// let original_scroll_position = use_signal(|| 0.0);
|
||||
/// use_effect((), move |_| {
|
||||
/// to_owned![original_scroll_position];
|
||||
/// async move {
|
||||
/// let window = web_sys::window().unwrap();
|
||||
/// let document = window.document().unwrap();
|
||||
/// let element = document.get_element_by_id("my_element").unwrap();
|
||||
/// element.scroll_into_view();
|
||||
/// original_scroll_position.set(window.scroll_y().unwrap());
|
||||
/// }
|
||||
///
|
||||
/// use_effect(move |_| async move {
|
||||
/// let window = web_sys::window().unwrap();
|
||||
/// let document = window.document().unwrap();
|
||||
/// let element = document.get_element_by_id("my_element").unwrap();
|
||||
/// element.scroll_into_view();
|
||||
/// original_scroll_position.set(window.scroll_y().unwrap());
|
||||
/// });
|
||||
///
|
||||
/// use_drop({
|
||||
/// to_owned![original_scroll_position];
|
||||
/// use_drop(move || {
|
||||
/// /// restore scroll to the top of the page
|
||||
/// move || {
|
||||
/// let window = web_sys::window().unwrap();
|
||||
/// window.scroll_with_x_and_y(*original_scroll_position.current(), 0.0);
|
||||
/// }
|
||||
/// let window = web_sys::window().unwrap();
|
||||
/// window.scroll_with_x_and_y(*original_scroll_position.current(), 0.0);
|
||||
/// });
|
||||
///
|
||||
/// rsx!{
|
||||
|
|
|
@ -46,33 +46,6 @@ pub(crate) mod innerlude {
|
|||
pub type Element = Option<VNode>;
|
||||
|
||||
/// 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,11 +20,7 @@ pub type TemplateId = &'static str;
|
|||
|
||||
/// 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
|
||||
/// 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.
|
||||
/// If the component returned early (e.g. `return None`), this will be Aborted(None)
|
||||
pub enum RenderReturn {
|
||||
/// A currently-available element
|
||||
Ready(VNode),
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
</p>
|
||||
</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
|
||||
|
||||
This overview provides a brief introduction to Dioxus. For a more in-depth guide, make sure to check out:
|
||||
|
|
|
@ -34,11 +34,11 @@ Remember: Dioxus is a library for declaring interactive user interfaces—it is
|
|||
|
||||
## 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`.
|
||||
|
||||
```rust, ignore
|
||||
```rust
|
||||
use dioxus::prelude::*;
|
||||
|
||||
fn main() {
|
||||
|
@ -49,7 +49,7 @@ fn main() {
|
|||
// It's not required, but highly recommended. For example, UpperCamelCase components will not generate a warning.
|
||||
#[component]
|
||||
fn App() -> Element {
|
||||
rsx!("hello world!")
|
||||
rsx! { "hello world!" }
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -67,25 +67,25 @@ children.
|
|||
```rust, ignore
|
||||
let value = "123";
|
||||
|
||||
rsx!(
|
||||
rsx! {
|
||||
div {
|
||||
class: "my-class {value}", // <--- attribute
|
||||
onclick: move |_| info!("clicked!"), // <--- listener
|
||||
h1 { "hello world" }, // <--- child
|
||||
}
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
The `rsx!` macro accepts attributes in "struct form" and will parse the rest
|
||||
of the body as child elements and rust expressions. Any rust expression that
|
||||
implements `IntoIterator<Item = impl IntoVNode>` will be parsed as a child.
|
||||
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.
|
||||
|
||||
```rust, ignore
|
||||
rsx!(
|
||||
rsx! {
|
||||
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.
|
||||
|
@ -93,7 +93,7 @@ The `rsx!` macro is what generates the `Element` that our components return.
|
|||
```rust, ignore
|
||||
#[component]
|
||||
fn Example() -> Element {
|
||||
rsx!("hello world")
|
||||
rsx!{ "hello world" }
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -104,20 +104,14 @@ elements:
|
|||
#[component]
|
||||
fn App() -> Element {
|
||||
let name = "dave";
|
||||
rsx!(
|
||||
rsx! {
|
||||
h1 { "Hello, {name}!" }
|
||||
div {
|
||||
class: "my-class",
|
||||
id: "my-id",
|
||||
|
||||
(0..5).map(|i| rsx!(
|
||||
div { key: "{i}"
|
||||
"FizzBuzz: {i}"
|
||||
}
|
||||
))
|
||||
|
||||
div { class: "my-class", id: "my-id",
|
||||
for i in 0..5 {
|
||||
div { "FizzBuzz: {i}" }
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -125,19 +119,19 @@ fn App() -> Element {
|
|||
|
||||
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
|
||||
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
|
||||
#[component]
|
||||
fn App() -> Element {
|
||||
rsx!(
|
||||
rsx! {
|
||||
Header {
|
||||
title: "My App",
|
||||
color: "red",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -154,12 +148,12 @@ struct HeaderProps {
|
|||
|
||||
#[component]
|
||||
fn Header(props: HeaderProps) -> Element {
|
||||
rsx!(
|
||||
rsx! {
|
||||
div {
|
||||
background_color: "{props.color}"
|
||||
h1 { "{props.title}" }
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -169,35 +163,12 @@ struct from function arguments:
|
|||
```rust, ignore
|
||||
#[component]
|
||||
fn Header(title: String, color: String) -> Element {
|
||||
rsx!(
|
||||
rsx! {
|
||||
div {
|
||||
background_color: "{color}"
|
||||
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:
|
||||
|
||||
```rust, ignore
|
||||
rsx!(
|
||||
rsx! {
|
||||
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
|
||||
|
||||
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 {
|
||||
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.
|
||||
|
||||
```rust, ignore
|
||||
fn use_mut_string() -> &mut String {
|
||||
fn use_mut_string() -> String {
|
||||
use_hook(|_| "Hello".to_string())
|
||||
}
|
||||
```
|
||||
|
@ -283,12 +242,12 @@ fn main() {
|
|||
|
||||
#[component]
|
||||
fn App() -> Element {
|
||||
let count = use_signal(|| 0);
|
||||
let mut count = use_signal(|| 0);
|
||||
|
||||
rsx!(
|
||||
div { "Count: {count}" }
|
||||
button { onclick: move |_| count.set(count + 1), "Increment" }
|
||||
button { onclick: move |_| count.set(count - 1), "Decrement" }
|
||||
button { onclick: move |_| count += 1, "Increment" }
|
||||
button { onclick: move |_| count -= 1, "Decrement" }
|
||||
)
|
||||
}
|
||||
```
|
||||
|
@ -311,21 +270,4 @@ Beyond this overview, Dioxus supports:
|
|||
- Basic fine-grained reactivity (IE SolidJS/Svelte)
|
||||
- and more!
|
||||
|
||||
Good luck!
|
||||
|
||||
## 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.
|
||||
Build cool things ✌️
|
||||
|
|
|
@ -76,13 +76,12 @@ fn main() {
|
|||
}
|
||||
//
|
||||
fn app() -> Element {
|
||||
let user_name = use_signal(|| "?".to_string());
|
||||
let permissions = use_signal(|| "?".to_string());
|
||||
let mut user_name = use_signal(|| "?".to_string());
|
||||
let mut permissions = use_signal(|| "?".to_string());
|
||||
|
||||
rsx! {
|
||||
div {
|
||||
button {
|
||||
onclick: move |_| {
|
||||
button { onclick: move |_| {
|
||||
async move {
|
||||
login().await.unwrap();
|
||||
}
|
||||
|
@ -92,12 +91,9 @@ fn app() -> Element {
|
|||
}
|
||||
div {
|
||||
button {
|
||||
onclick: move |_| {
|
||||
to_owned![user_name];
|
||||
async move {
|
||||
if let Ok(data) = get_user_name().await {
|
||||
user_name.set(data);
|
||||
}
|
||||
onclick: move |_| async move {
|
||||
if let Ok(data) = get_user_name().await {
|
||||
user_name.set(data);
|
||||
}
|
||||
},
|
||||
"Get User Name"
|
||||
|
@ -106,12 +102,9 @@ fn app() -> Element {
|
|||
}
|
||||
div {
|
||||
button {
|
||||
onclick: move |_| {
|
||||
to_owned![permissions];
|
||||
async move {
|
||||
if let Ok(data) = get_permissions().await {
|
||||
permissions.set(data);
|
||||
}
|
||||
onclick: move |_| async move {
|
||||
if let Ok(data) = get_permissions().await {
|
||||
permissions.set(data);
|
||||
}
|
||||
},
|
||||
"Get Permissions"
|
||||
|
|
|
@ -3,21 +3,18 @@ use dioxus::prelude::*;
|
|||
|
||||
pub fn app() -> Element {
|
||||
let mut count = use_signal(|| 0);
|
||||
let text = use_signal(|| "...".to_string());
|
||||
let mut text = use_signal(|| "...".to_string());
|
||||
|
||||
rsx! {
|
||||
h1 { "High-Five counter: {count}" }
|
||||
button { onclick: move |_| count += 1, "Up high!" }
|
||||
button { onclick: move |_| count -= 1, "Down low!" }
|
||||
button {
|
||||
onclick: move |_| {
|
||||
to_owned![text];
|
||||
async move {
|
||||
if let Ok(data) = get_server_data().await {
|
||||
println!("Client received: {}", data);
|
||||
text.set(data.clone());
|
||||
post_server_data(data).await.unwrap();
|
||||
}
|
||||
onclick: move |_| async move {
|
||||
if let Ok(data) = get_server_data().await {
|
||||
println!("Client received: {}", data);
|
||||
text.set(data.clone());
|
||||
post_server_data(data).await.unwrap();
|
||||
}
|
||||
},
|
||||
"Run a server function"
|
||||
|
|
|
@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
fn app() -> Element {
|
||||
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)?;
|
||||
|
||||
rsx! {
|
||||
|
@ -18,14 +18,11 @@ fn app() -> Element {
|
|||
button { onclick: move |_| count += 1, "Up high!" }
|
||||
button { onclick: move |_| count -= 1, "Down low!" }
|
||||
button {
|
||||
onclick: move |_| {
|
||||
to_owned![text];
|
||||
async move {
|
||||
if let Ok(data) = get_server_data().await {
|
||||
println!("Client received: {}", data);
|
||||
text.set(data.clone());
|
||||
post_server_data(data).await.unwrap();
|
||||
}
|
||||
onclick: move |_| async move {
|
||||
if let Ok(data) = get_server_data().await {
|
||||
println!("Client received: {}", data);
|
||||
text.set(data.clone());
|
||||
post_server_data(data).await.unwrap();
|
||||
}
|
||||
},
|
||||
"Run a server function!"
|
||||
|
|
|
@ -15,9 +15,7 @@ fn main() {
|
|||
}
|
||||
|
||||
fn app() -> Element {
|
||||
rsx! {
|
||||
Router::<Route> {}
|
||||
}
|
||||
rsx! { Router::<Route> {} }
|
||||
}
|
||||
|
||||
#[derive(Clone, Routable, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
|
@ -50,28 +48,20 @@ fn Blog(id: i32) -> Element {
|
|||
#[component]
|
||||
fn Home() -> Element {
|
||||
let mut count = use_signal(|| 0);
|
||||
let text = use_signal(|| "...".to_string());
|
||||
let mut text = use_signal(|| "...".to_string());
|
||||
|
||||
rsx! {
|
||||
Link {
|
||||
to: Route::Blog {
|
||||
id: count()
|
||||
},
|
||||
"Go to blog"
|
||||
}
|
||||
Link { to: Route::Blog { id: count() }, "Go to blog" }
|
||||
div {
|
||||
h1 { "High-Five counter: {count}" }
|
||||
button { onclick: move |_| count += 1, "Up high!" }
|
||||
button { onclick: move |_| count -= 1, "Down low!" }
|
||||
button {
|
||||
onclick: move |_| {
|
||||
to_owned![text];
|
||||
async move {
|
||||
if let Ok(data) = get_server_data().await {
|
||||
println!("Client received: {}", data);
|
||||
text.set(data.clone());
|
||||
post_server_data(data).await.unwrap();
|
||||
}
|
||||
onclick: move |_| async move {
|
||||
if let Ok(data) = get_server_data().await {
|
||||
println!("Client received: {}", data);
|
||||
text.set(data.clone());
|
||||
post_server_data(data).await.unwrap();
|
||||
}
|
||||
},
|
||||
"Run server function!"
|
||||
|
|
|
@ -30,16 +30,13 @@
|
|||
//! }
|
||||
//!
|
||||
//! fn app() -> Element {
|
||||
//! let text = use_signal(|| "...".to_string());
|
||||
//! let mut text = use_signal(|| "...".to_string());
|
||||
//!
|
||||
//! rsx! {
|
||||
//! button {
|
||||
//! onclick: move |_| {
|
||||
//! to_owned![text];
|
||||
//! async move {
|
||||
//! if let Ok(data) = get_server_data().await {
|
||||
//! text.set(data);
|
||||
//! }
|
||||
//! onclick: move |_| async move {
|
||||
//! if let Ok(data) = get_server_data().await {
|
||||
//! text.set(data);
|
||||
//! }
|
||||
//! },
|
||||
//! "Run a server function"
|
||||
|
|
|
@ -32,10 +32,6 @@
|
|||
|
||||
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
|
||||
|
||||
- Report issues on our [issue tracker](https://github.com/dioxuslabs/dioxus/issues).
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")]
|
||||
|
||||
#[macro_export]
|
||||
/// A helper macro for using hooks and properties in async environments.
|
||||
/// A helper macro for cloning multiple values at once
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
|
|
Loading…
Reference in a new issue