Remove some old docs, cleanup some readmes

This commit is contained in:
Jonathan Kelley 2024-03-27 17:28:30 -07:00
parent a1c03a461d
commit 537f064001
No known key found for this signature in database
GPG key ID: 1FBB50F7EB0A08BE
12 changed files with 81 additions and 203 deletions

View file

@ -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!{

View file

@ -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;
}

View file

@ -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),

View file

@ -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:

View file

@ -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 ✌️

View file

@ -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"

View file

@ -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"

View file

@ -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!"

View file

@ -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!"

View file

@ -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"

View file

@ -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).

View file

@ -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
///