Feat: index.html
This commit is contained in:
1 parent
a2406b33d6
commit
689e017108
14 files changed
+1
No files matched your search
@@ -0,0 +1,37 @@
|
||||
# Dioxus Chapter 0 - Intro + Index
|
||||
|
||||
|
||||
|
||||
## Guides
|
||||
------------------
|
||||
| Chapter | Description |
|
||||
| ------------------ | ------------------------------------------ |
|
||||
| 1-hello-world | Intro to Dioxus |
|
||||
| 2-utilities | Tools to make writing apps easier |
|
||||
| 3-vnode-macros | VNodes and the html! macro |
|
||||
| 4-hooks | Renderer + event integration using web_sys |
|
||||
| 5-context-api | Virtual DOM, patching/diffing |
|
||||
| 6-subscription API | Standard bundle of useful hooks |
|
||||
| 7-hello-world | Html + functional_component macro |
|
||||
| 8-hello-world | Blessed state management solutions |
|
||||
| 9-hello-world | Renderer + event integration using web_sys |
|
||||
| 10-hello-world | Renderer + event integration using web_sys |
|
||||
|
||||
## Development
|
||||
------------------
|
||||
| Package | Use |
|
||||
| ------- | ------------------------------------------------ |
|
||||
| full | Batteries-included entrypoint with feature flags |
|
||||
| core | Virtual DOM, diffing, patching, and events |
|
||||
| hooks | Standard hooks |
|
||||
| macro | Html + functional_component macro |
|
||||
| web | Renderer + event integration using web_sys |
|
||||
| live | Dedicated isomorphic framework |
|
||||
| recoil | Data-flow-graph state management |
|
||||
| redux | Reducer-style state management |
|
||||
| bearly | Simple and idiomatic state management |
|
||||
|
||||
## Books
|
||||
---------------
|
||||
Book of patterns
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# Hello, World!
|
||||
|
||||
Dioxus should look and feel just like writing functional React components. In Dioxus, there are no class components with lifecycles. All state management is done via hooks. This encourages logic resusability and lessens the burden on Dioxus to maintain a non-breaking lifecycle API.
|
||||
|
||||
```rust
|
||||
#[derive(Properties, PartialEq)]
|
||||
struct MyProps {
|
||||
name: String
|
||||
}
|
||||
|
||||
fn Example(ctx: Context<MyProps>) -> VNode {
|
||||
html! { <div> "Hello {ctx.props().name}!" </div> }
|
||||
}
|
||||
```
|
||||
|
||||
For functions to be valid components, they must take the `Context` object which is generic over some properties. The properties parameter must implement the `Properties` trait, which can be automatically derived. Whenever the input properties of a component changes, the function component will be re-ran and a new set of VNodes will be generated.
|
||||
@@ -0,0 +1,84 @@
|
||||
# Concurrent mode
|
||||
|
||||
Concurrent mode provides a mechanism for building efficient asynchronous components. With this feature, components don't need to render immediately, and instead can schedule a future render by returning a future.
|
||||
|
||||
To make a component asynchronous, simply change its function signature to async.
|
||||
|
||||
```rust
|
||||
fn Example(ctx: Context<()>) -> Vnode {
|
||||
rsx!{ <div> "Hello world!" </div> }
|
||||
}
|
||||
```
|
||||
becomes
|
||||
|
||||
```rust
|
||||
async fn Example(ctx: Context<()>) -> Vnode {
|
||||
rsx!{ <div> "Hello world!" </div> }
|
||||
}
|
||||
```
|
||||
|
||||
Now, logic in components can be awaited to delay updates of the component and its children. Like so:
|
||||
|
||||
```rust
|
||||
async fn Example(ctx: Context<()>) -> Vnode {
|
||||
let name = fetch_name().await;
|
||||
rsx!{ <div> "Hello {name}" </div> }
|
||||
}
|
||||
|
||||
async fetch_name() -> String {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
This component will only schedule its render once the fetch is complete. However, we *don't* recommend using async/await directly in your components.
|
||||
|
||||
Async is a notoriously challenging yet rewarding tool for efficient tools. If not careful, locking and unlocking shared aspects of the component's context can lead to data races and panics. If a shared resource is locked while the component is awaiting, then other components can be locked or panic when trying to access the same resource. These rules are especially important when references to shared global state are accessed using the context object's lifetime. If mutable references to data captured immutably by the context are taken, then the component will panic, and cause confusion.
|
||||
|
||||
Instead, we suggest using hooks and future combinators that can safely utilize the safe guards of the component's Context when interacting with async tasks.
|
||||
|
||||
As part of our Dioxus hooks crate, we provide a data loader hook which pauses a component until its async dependencies are ready. This caches requests, reruns the fetch if dependencies have changed, and provides the option to render something else while the component is loading.
|
||||
|
||||
```rust
|
||||
async fn ExampleLoader(ctx: Context<()>) -> Vnode {
|
||||
/*
|
||||
Fetch, pause the component from rendering at all.
|
||||
|
||||
The component is locked while waiting for the request to complete
|
||||
While waiting, an alternate component is scheduled in its place.
|
||||
|
||||
This API stores the result on the Context object, so the loaded data is taken as reference.
|
||||
*/
|
||||
let name: &Result<SomeStructure> = use_fetch_data("http://example.com/json", ())
|
||||
.place_holder(|ctx| rsx!{<div> "loading..." </div>})
|
||||
.delayed_place_holder(1000, |ctx| rsx!{ <div> "still loading..." </div>})
|
||||
.await;
|
||||
|
||||
match name {
|
||||
Ok(name) => rsx! { <div> "Hello {something}" </div> },
|
||||
Err(e) => rsx! { <div> "An error occured :(" </div>}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
```rust
|
||||
async fn Example(ctx: Context<()>) -> VNode {
|
||||
// Diff this set between the last set
|
||||
// Check if we have any outstanding tasks?
|
||||
//
|
||||
// Eventually, render the component into the VDOM when the future completes
|
||||
<div>
|
||||
<Example />
|
||||
</div>
|
||||
|
||||
// Render a div, queue a component
|
||||
// Render the placeholder first, then when the component is ready, then render the component
|
||||
<div>
|
||||
<Suspense placeholder={html!{<div>"Loading"</div>}}>
|
||||
<Example />
|
||||
</Suspense>
|
||||
</div>
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,56 @@
|
||||
# Memoization and the arena allocator
|
||||
|
||||
Dioxus differs slightly from other UI virtual doms in some subtle ways due to its memory allocator.
|
||||
|
||||
One important aspect to understand is how props are passed down from parent components to children. All "components" (custom user-made UI elements) are tightly allocated together in an arena. However, because props and hooks are generically typed, they are casted to any and allocated on the heap - not in the arena with the components.
|
||||
|
||||
With this system, we try to be more efficient when leaving the component arena and entering the heap. By default, props are memoized between renders using COW and context. This makes props comparisons fast - done via ptr comparisons on the cow pointer. Because memoization is done by default, parent re-renders will *not* cascade to children if the child's props did not change.
|
||||
|
||||
https://dmitripavlutin.com/use-react-memo-wisely/
|
||||
|
||||
This behavior is defined as an implicit attribute to user components. When in React land you might wrap a component is `react.memo`, Dioxus components are automatically memoized via an implicit attribute. You can manually configure this behavior on any component with "nomemo" to disable memoization.
|
||||
|
||||
```rust
|
||||
fn test() -> VNode {
|
||||
html! {
|
||||
<>
|
||||
<SomeComponent nomemo />
|
||||
// same as
|
||||
<SomeComponent nomemo=true />
|
||||
</>
|
||||
}
|
||||
}
|
||||
|
||||
static TestComponent: FC<()> = |ctx| html!{<div>"Hello world"</div>};
|
||||
|
||||
static TestComponent: FC<()> = |ctx| {
|
||||
let g = "BLAH";
|
||||
html! {
|
||||
<div> "Hello world" </div>
|
||||
}
|
||||
};
|
||||
|
||||
#[functional_component]
|
||||
static TestComponent: FC<{ name: String }> = |ctx| html! { <div> "Hello {name}" </div> };
|
||||
```
|
||||
|
||||
## Why this behavior?
|
||||
|
||||
"This is different than React, why differ?".
|
||||
|
||||
Take a component likes this:
|
||||
|
||||
```rust
|
||||
fn test(ctx: Context<()>) -> VNode {
|
||||
let Bundle { alpha, beta, gamma } = use_context::<SomeContext>(ctx);
|
||||
html! {
|
||||
<div>
|
||||
<Component name=alpha />
|
||||
<Component name=beta />
|
||||
<Component name=gamma />
|
||||
</div>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
While the contents of the destructued bundle might change, not every child component will need to be re-rendered.
|
||||
@@ -0,0 +1,32 @@
|
||||
# Dioxus Liveview
|
||||
Liveview is a configuration where a server and a client work together to render a Dioxus app. Liveview monomorphizes a web application, eliminating the need for frontend-specific APIs.
|
||||
|
||||
This is a developer-friendly alternative to the JAM-stack (Javascript + API + Markdown), combining the WASM-compatibility and async performance of Rust.
|
||||
|
||||
## Why liveview?
|
||||
|
||||
### No APIs necessary!
|
||||
Because Liveview combines the server and the client, you'll find dedicated APIs unnecessary. You'll still want to implement a datafetching service for Live-apps, but this can be implemented as a crate and shared between apps. This approach was designed to let you model out your data requirements without needing to maintain a public versioned API.
|
||||
|
||||
You can find more information to data modeling and fetching for LiveApps in the "Book of Dioxus Patterns".
|
||||
|
||||
### Ease of deployment
|
||||
There is no hassle for deploying Dioxus liveview apps - simply upload the binary to your hosting provider of choice. There simply is no need to deal with intermediate APIs. An app's frontend and backend are tightly coupled to each other, meaning that the backed and frontend are always up to date.
|
||||
|
||||
This is especially powerful for small teams, where fast iteration, versioned unique prototypes, and simple deployments are important. As your app grows, Dioxus will happily grow with you, serving up to 100K RPS (thanks to async Rust performance).
|
||||
|
||||
### Power of server rendering combined with the reactive nature of JavaScript
|
||||
Liveview apps are backed by a server and enhanced with web-assembly. This completely eliminates the need to write Javascript to add dynamic content to webpages. Apps are written in only **one** language and require essentially 0 knowledge of build systems, transpiling or ECMAScript versions. Minimum browser support is guaranteed to cover 95% of users, and the Dioxus-CLI can be configured to generate polyfills for even more support.
|
||||
|
||||
### Support with LiveHost by Dioxus-Labs
|
||||
The Dioxus-CLI comes ready for use with premium Dioxus-Labs services, like LiveHost. Simply link up your git repo to the Dioxus LiveHost and start deploying your fullstack Dioxus app today. LiveHost supports:
|
||||
|
||||
- Versioned fronted/backend with unique links
|
||||
- Builtin CI/CD
|
||||
- Managed and pluggable storage database backends
|
||||
- Serverless support for minimal latency
|
||||
- Site Analytics
|
||||
- Lighthouse optimization
|
||||
- On-premise support (see license terms)
|
||||
|
||||
Dioxus LiveHost is a Dioxus LiveApp management service with all supported features in a single binary. For OSS, we permit free usage and deployment of LiveHost to your favorite hosting provider.
|
||||
@@ -0,0 +1,58 @@
|
||||
# Utilities
|
||||
|
||||
There are a few macros and utility functions that make life easier when writing Dioxus components.
|
||||
|
||||
|
||||
## The `functional_component` procedural macro
|
||||
The `functional_component` proc macro allows you to inline props into the generic parameter of the component's context. This is useful When writing "pure" components, or when you don't want the extra clutter of structs, derives, and burden of naming things.
|
||||
|
||||
This macro allows allows a classic struct definition to be embedded directly into the function arguments. The props are automatically pulled from the context and destructured into the function's body, saving an extra step.
|
||||
|
||||
```rust
|
||||
// Inlines and destructure props *automatically*
|
||||
#[functional_component]
|
||||
fn Example(ctx: &mut Context<{
|
||||
name: String
|
||||
pending: bool
|
||||
count: i32
|
||||
}>) -> VNode {
|
||||
html! {
|
||||
<div>
|
||||
<p> "Hello, {name}!" </p>
|
||||
<p> "Status: {pending}!" </p>
|
||||
<p> "Count {count}!" </p>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
becomes this:
|
||||
|
||||
```rust
|
||||
#[derive(Debug, Properties, PartialEq)]
|
||||
struct ExampleProps {
|
||||
name: String
|
||||
pending: bool
|
||||
count: i32
|
||||
};
|
||||
|
||||
fn Example(ctx: &mut Context<ExampleProps>) -> VNode {
|
||||
let ExampleProps {
|
||||
name, pending, count
|
||||
} = ctx.props();
|
||||
|
||||
rsx! {
|
||||
<div>
|
||||
<p> "Hello, {name}!" </p>
|
||||
<p> "Status: {pending}!" </p>
|
||||
<p> "Count {count}!" </p>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## The rsx! macro
|
||||
|
||||
The rsx! macacro is similar to the html! macro in other libraries, but with a few add-ons to make it fun and easy to work with. We'll cover the rsx macro more in depth in the [vnode-macro](3-vnode-macros.md) chapter.
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
```rust
|
||||
fn Example(ctx: &mut Context<()>) -> VNode {
|
||||
let service = use_combubulator(ctx);
|
||||
let Status { name, pending, count } = service.info();
|
||||
html! {
|
||||
<div>
|
||||
<p> "Hello, {name}!" </p>
|
||||
<p> "Status: {pending}!" </p>
|
||||
<p> "Count {count}!" </p>
|
||||
<button onclick=|_| service.update()>
|
||||
"Refresh services"
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,47 @@
|
||||
# Context API
|
||||
|
||||
|
||||
|
||||
```rust
|
||||
// Create contexts available to children
|
||||
// Only one context can be associated with any given component
|
||||
// This is known as "exposed state". Children can access this context,
|
||||
// but will not be automatically subscribed.
|
||||
fn ContextCreate(ctx: &mut Context<()>) -> VNode {
|
||||
let context = ctx.set_context(|| CustomContext::new());
|
||||
html! { <> {ctx.children()} </> }
|
||||
}
|
||||
|
||||
fn ContextRead(ctx: &mut Context<()>) -> VNode {
|
||||
// Panics if context is not available
|
||||
let some_ctx = ctx.get_context::<CustomContext>();
|
||||
let text = some_ctx.select("some_selector");
|
||||
html! { <div> "{text}" </div> }
|
||||
}
|
||||
|
||||
fn Subscription(ctx: &mut Context<()>) -> VNode {
|
||||
// Open a "port" on the component for actions to trigger a re-evaluation
|
||||
let subscription = ctx.new_subscription();
|
||||
|
||||
// A looping timer - the effect is re-called on every re-evaluation
|
||||
use_async_effect(ctx, move || async {
|
||||
timer::new(2000).await;
|
||||
subscription.call();
|
||||
}, None);
|
||||
|
||||
// A one-shot timer, the deps don't change so the effect only happens once
|
||||
use_async_effect_deps(ctx, move || async {
|
||||
timer::new(2000).await;
|
||||
subscription.call();
|
||||
}, ());
|
||||
}
|
||||
|
||||
// Mix subscriptions and context to make a simple Redux
|
||||
fn use_global_state<T: UserContextTrait>(ctx: &mut Context<()>) -> T {
|
||||
let some_ctx = ctx.get_context::<T>();
|
||||
let component_subscription = ctx.new_subscription();
|
||||
some_ctx.subscribe_component(component_subscription);
|
||||
some_ctx
|
||||
}
|
||||
|
||||
```
|
||||
@@ -0,0 +1,37 @@
|
||||
# Subscriptions
|
||||
|
||||
Yew subscriptions are used to schedule update for components into the future. The `Context` object can create subscriptions:
|
||||
|
||||
```rust
|
||||
fn Component(ctx: Component<()>) -> VNode {
|
||||
let update = ctx.schedule();
|
||||
|
||||
// Now, when the subscription is called, the component will be re-evaluted
|
||||
update.consume();
|
||||
}
|
||||
```
|
||||
|
||||
Whenever a component's subscription is called, the component will then re-evaluated. You can consider the input properties of
|
||||
a component to be just another form of subscription. By default, the Dioxus component system automatically diffs a component's props
|
||||
when the parent function is called, and if the props are different, the child component's subscription is called.
|
||||
|
||||
The subscription API exposes this functionality allowing hooks and state management solutions the ability to update components whenever
|
||||
some state or event occurs outside of the component. For instance, the `use_context` hook uses this to subscribe components that use a
|
||||
particular context.
|
||||
|
||||
|
||||
```rust
|
||||
fn use_context<I>(ctx: Context<T>) -> I {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
Whitespace-only changes.
@@ -0,0 +1 @@
|
||||
# Custom Renderer
|
||||
Whitespace-only changes.
Reference in new issue
Block a user