chore: rename all &cx to cx, make clipppy happy
This commit is contained in:
1 parent
e8133e9449
commit
4eefc3f854
85 files changed
+256
-271
No files matched your search
@@ -6,7 +6,7 @@ fn main() {
|
||||
}
|
||||
|
||||
pub fn App(cx: Scope) -> Element {
|
||||
let is_logged_in = use_state(&cx, || false);
|
||||
let is_logged_in = use_state(cx, || false);
|
||||
|
||||
cx.render(rsx!(LogIn {
|
||||
is_logged_in: **is_logged_in,
|
||||
|
||||
@@ -17,13 +17,13 @@ fn App(cx: Scope) -> Element {
|
||||
// But `if` statements only run if the conditional is true!
|
||||
// So we might violate rule 2.
|
||||
if you_are_happy && you_know_it {
|
||||
let something = use_state(&cx, || "hands");
|
||||
let something = use_state(cx, || "hands");
|
||||
println!("clap your {something}")
|
||||
}
|
||||
|
||||
// ✅ instead, *always* call use_state
|
||||
// You can put other stuff in the conditional though
|
||||
let something = use_state(&cx, || "hands");
|
||||
let something = use_state(cx, || "hands");
|
||||
if you_are_happy && you_know_it {
|
||||
println!("clap your {something}")
|
||||
}
|
||||
@@ -33,12 +33,12 @@ fn App(cx: Scope) -> Element {
|
||||
// ❌ don't call hooks inside closures!
|
||||
// We can't guarantee that the closure, if used, will be called at the same time every time
|
||||
let _a = || {
|
||||
let b = use_state(&cx, || 0);
|
||||
let b = use_state(cx, || 0);
|
||||
b.get()
|
||||
};
|
||||
|
||||
// ✅ instead, move hook `b` outside
|
||||
let b = use_state(&cx, || 0);
|
||||
let b = use_state(cx, || 0);
|
||||
let _a = || b.get();
|
||||
// ANCHOR_END: closure
|
||||
|
||||
@@ -50,12 +50,12 @@ fn App(cx: Scope) -> Element {
|
||||
// ❌ Do not use hooks in loops!
|
||||
// In this case, if the length of the Vec changes, we break rule 2
|
||||
for _name in &names {
|
||||
let is_selected = use_state(&cx, || false);
|
||||
let is_selected = use_state(cx, || false);
|
||||
println!("selected: {is_selected}");
|
||||
}
|
||||
|
||||
// ✅ Instead, use a hashmap with use_ref
|
||||
let selection_map = use_ref(&cx, HashMap::<&str, bool>::new);
|
||||
let selection_map = use_ref(cx, HashMap::<&str, bool>::new);
|
||||
|
||||
for name in &names {
|
||||
let is_selected = selection_map.read()[name];
|
||||
|
||||
@@ -7,7 +7,7 @@ fn main() {
|
||||
|
||||
// ANCHOR: component
|
||||
fn App(cx: Scope) -> Element {
|
||||
let mut count = use_state(&cx, || 0);
|
||||
let mut count = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx!(
|
||||
h1 { "High-Five counter: {count}" }
|
||||
|
||||
@@ -8,8 +8,8 @@ fn main() {
|
||||
// ANCHOR: component
|
||||
fn App(cx: Scope) -> Element {
|
||||
// ANCHOR: use_state_calls
|
||||
let mut count_a = use_state(&cx, || 0);
|
||||
let mut count_b = use_state(&cx, || 0);
|
||||
let mut count_a = use_state(cx, || 0);
|
||||
let mut count_b = use_state(cx, || 0);
|
||||
// ANCHOR_END: use_state_calls
|
||||
|
||||
cx.render(rsx!(
|
||||
|
||||
@@ -7,7 +7,7 @@ fn main() {
|
||||
|
||||
// ANCHOR: component
|
||||
fn App(cx: Scope) -> Element {
|
||||
let list = use_ref(&cx, Vec::new);
|
||||
let list = use_ref(cx, Vec::new);
|
||||
let list_formatted = format!("{:?}", *list.read());
|
||||
|
||||
cx.render(rsx!(
|
||||
|
||||
@@ -7,7 +7,7 @@ fn main() {
|
||||
|
||||
// ANCHOR: component
|
||||
fn App(cx: Scope) -> Element {
|
||||
let name = use_state(&cx, || "bob".to_string());
|
||||
let name = use_state(cx, || "bob".to_string());
|
||||
|
||||
cx.render(rsx! {
|
||||
input {
|
||||
|
||||
@@ -18,7 +18,7 @@ fn MemeEditor(cx: Scope) -> Element {
|
||||
width: fit-content;
|
||||
";
|
||||
|
||||
let caption = use_state(&cx, || "me waiting for my rust code to compile".to_string());
|
||||
let caption = use_state(cx, || "me waiting for my rust code to compile".to_string());
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
@@ -14,10 +14,10 @@ struct DarkMode(bool);
|
||||
|
||||
pub fn App(cx: Scope) -> Element {
|
||||
// ANCHOR: context_provider
|
||||
use_context_provider(&cx, || DarkMode(false));
|
||||
use_context_provider(cx, || DarkMode(false));
|
||||
// ANCHOR_END: context_provider
|
||||
|
||||
let is_dark_mode = use_is_dark_mode(&cx);
|
||||
let is_dark_mode = use_is_dark_mode(cx);
|
||||
|
||||
let wrapper_style = if is_dark_mode {
|
||||
r"
|
||||
@@ -47,7 +47,7 @@ pub fn use_is_dark_mode(cx: &ScopeState) -> bool {
|
||||
|
||||
// ANCHOR: toggle
|
||||
pub fn DarkModeToggle(cx: Scope) -> Element {
|
||||
let dark_mode = use_context::<DarkMode>(&cx)?;
|
||||
let dark_mode = use_context::<DarkMode>(cx)?;
|
||||
|
||||
let style = if dark_mode.read().0 {
|
||||
"color:white"
|
||||
@@ -71,7 +71,7 @@ pub fn DarkModeToggle(cx: Scope) -> Element {
|
||||
|
||||
// ANCHOR: meme_editor
|
||||
fn MemeEditor(cx: Scope) -> Element {
|
||||
let is_dark_mode = use_is_dark_mode(&cx);
|
||||
let is_dark_mode = use_is_dark_mode(cx);
|
||||
let heading_style = if is_dark_mode { "color: white" } else { "" };
|
||||
|
||||
let container_style = r"
|
||||
@@ -82,7 +82,7 @@ fn MemeEditor(cx: Scope) -> Element {
|
||||
width: fit-content;
|
||||
";
|
||||
|
||||
let caption = use_state(&cx, || "me waiting for my rust code to compile".to_string());
|
||||
let caption = use_state(cx, || "me waiting for my rust code to compile".to_string());
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
@@ -152,7 +152,7 @@ fn CaptionEditor<'a>(
|
||||
caption: &'a str,
|
||||
on_input: EventHandler<'a, FormData>,
|
||||
) -> Element<'a> {
|
||||
let is_dark_mode = use_is_dark_mode(&cx);
|
||||
let is_dark_mode = use_is_dark_mode(cx);
|
||||
|
||||
let colors = if is_dark_mode {
|
||||
r"
|
||||
|
||||
@@ -14,9 +14,9 @@ struct Comment {
|
||||
|
||||
pub fn App(cx: Scope) -> Element {
|
||||
// ANCHOR: render_list
|
||||
let comment_field = use_state(&cx, String::new);
|
||||
let mut next_id = use_state(&cx, || 0);
|
||||
let comments = use_ref(&cx, Vec::<Comment>::new);
|
||||
let comment_field = use_state(cx, String::new);
|
||||
let mut next_id = use_state(cx, || 0);
|
||||
let comments = use_ref(cx, Vec::<Comment>::new);
|
||||
|
||||
let comments_lock = comments.read();
|
||||
let comments_rendered = comments_lock.iter().map(|comment| {
|
||||
|
||||
@@ -8,7 +8,7 @@ fn main() {
|
||||
|
||||
fn App(cx: Scope) -> Element {
|
||||
// ANCHOR: spawn
|
||||
let logged_in = use_state(&cx, || false);
|
||||
let logged_in = use_state(cx, || false);
|
||||
|
||||
let log_in = move |_| {
|
||||
cx.spawn({
|
||||
@@ -62,10 +62,10 @@ pub fn Tokio(cx: Scope) -> Element {
|
||||
}
|
||||
|
||||
pub fn ToOwnedMacro(cx: Scope) -> Element {
|
||||
let count = use_state(&cx, || 0);
|
||||
let age = use_state(&cx, || 0);
|
||||
let name = use_state(&cx, || 0);
|
||||
let description = use_state(&cx, || 0);
|
||||
let count = use_state(cx, || 0);
|
||||
let age = use_state(cx, || 0);
|
||||
let name = use_state(cx, || 0);
|
||||
let description = use_state(cx, || 0);
|
||||
|
||||
let _ = || {
|
||||
// ANCHOR: to_owned_macro
|
||||
|
||||
@@ -14,7 +14,7 @@ struct ApiResponse {
|
||||
|
||||
fn App(cx: Scope) -> Element {
|
||||
// ANCHOR: use_future
|
||||
let future = use_future(&cx, (), |_| async move {
|
||||
let future = use_future(cx, (), |_| async move {
|
||||
reqwest::get("https://dog.ceo/api/breeds/image/random")
|
||||
.await
|
||||
.unwrap()
|
||||
@@ -47,7 +47,7 @@ fn App(cx: Scope) -> Element {
|
||||
#[inline_props]
|
||||
fn RandomDog(cx: Scope, breed: String) -> Element {
|
||||
// ANCHOR: dependency
|
||||
let future = use_future(&cx, (breed,), |(breed,)| async move {
|
||||
let future = use_future(cx, (breed,), |(breed,)| async move {
|
||||
reqwest::get(format!("https://dog.ceo/api/breed/{breed}/images/random"))
|
||||
.await
|
||||
.unwrap()
|
||||
|
||||
@@ -12,7 +12,7 @@ Your component today might look something like this:
|
||||
|
||||
```rust
|
||||
fn Comp(cx: Scope) -> DomTree {
|
||||
let (title, set_title) = use_state(&cx, || "Title".to_string());
|
||||
let (title, set_title) = use_state(cx, || "Title".to_string());
|
||||
cx.render(rsx!{
|
||||
input {
|
||||
value: title,
|
||||
@@ -26,7 +26,7 @@ This component is fairly straightforward – the input updates its own value on
|
||||
|
||||
```rust
|
||||
fn Comp(cx: Scope) -> DomTree {
|
||||
let (title, set_title) = use_state(&cx, || "Title".to_string());
|
||||
let (title, set_title) = use_state(cx, || "Title".to_string());
|
||||
cx.render(rsx!{
|
||||
div {
|
||||
input {
|
||||
@@ -49,7 +49,7 @@ We can use signals to generate a two-way binding between data and the input box.
|
||||
|
||||
```rust
|
||||
fn Comp(cx: Scope) -> DomTree {
|
||||
let mut title = use_signal(&cx, || String::from("Title"));
|
||||
let mut title = use_signal(cx, || String::from("Title"));
|
||||
cx.render(rsx!(input { value: title }))
|
||||
}
|
||||
```
|
||||
@@ -58,8 +58,8 @@ For a slightly more interesting example, this component calculates the sum betwe
|
||||
|
||||
```rust
|
||||
fn Calculator(cx: Scope) -> DomTree {
|
||||
let mut a = use_signal(&cx, || 0);
|
||||
let mut b = use_signal(&cx, || 0);
|
||||
let mut a = use_signal(cx, || 0);
|
||||
let mut b = use_signal(cx, || 0);
|
||||
let mut c = a + b;
|
||||
rsx! {
|
||||
input { value: a }
|
||||
@@ -72,8 +72,8 @@ fn Calculator(cx: Scope) -> DomTree {
|
||||
Do you notice how we can use built-in operations on signals? Under the hood, we actually create a new derived signal that depends on `a` and `b`. Whenever `a` or `b` update, then `c` will update. If we need to create a new derived signal that's more complex than a basic operation (`std::ops`) we can either chain signals together or combine them:
|
||||
|
||||
```rust
|
||||
let mut a = use_signal(&cx, || 0);
|
||||
let mut b = use_signal(&cx, || 0);
|
||||
let mut a = use_signal(cx, || 0);
|
||||
let mut b = use_signal(cx, || 0);
|
||||
|
||||
// Chain signals together using the `with` method
|
||||
let c = a.with(b).map(|(a, b)| *a + *b);
|
||||
@@ -84,7 +84,7 @@ let c = a.with(b).map(|(a, b)| *a + *b);
|
||||
If we ever need to get the value out of a signal, we can simply `deref` it.
|
||||
|
||||
```rust
|
||||
let mut a = use_signal(&cx, || 0);
|
||||
let mut a = use_signal(cx, || 0);
|
||||
let c = *a + *b;
|
||||
```
|
||||
|
||||
@@ -97,7 +97,7 @@ Sometimes you want a signal to propagate across your app, either through far-awa
|
||||
```rust
|
||||
const TITLE: Atom<String> = || "".to_string();
|
||||
const Provider: Component = |cx|{
|
||||
let title = use_signal(&cx, &TITLE);
|
||||
let title = use_signal(cx, &TITLE);
|
||||
render!(input { value: title })
|
||||
};
|
||||
```
|
||||
@@ -106,7 +106,7 @@ If we use the `TITLE` atom in another component, we can cause updates to flow be
|
||||
|
||||
```rust
|
||||
const Receiver: Component = |cx|{
|
||||
let title = use_signal(&cx, &TITLE);
|
||||
let title = use_signal(cx, &TITLE);
|
||||
log::info!("This will only be called once!");
|
||||
rsx!(cx,
|
||||
div {
|
||||
@@ -133,7 +133,7 @@ Dioxus automatically understands how to use your signals when mixed with iterato
|
||||
```rust
|
||||
const DICT: AtomFamily<String, String> = |_| {};
|
||||
const List: Component = |cx|{
|
||||
let dict = use_signal(&cx, &DICT);
|
||||
let dict = use_signal(cx, &DICT);
|
||||
cx.render(rsx!(
|
||||
ul {
|
||||
For { each: dict, map: |k, v| rsx!( li { "{v}" }) }
|
||||
|
||||
@@ -59,7 +59,7 @@ If we represented the reactive graph presented above in Dioxus, it would look ve
|
||||
// Declare a component that holds our datasources and calculates `g`
|
||||
fn RenderGraph(cx: Scope) -> Element {
|
||||
let seconds = use_datasource(SECONDS);
|
||||
let constant = use_state(&cx, || 1);
|
||||
let constant = use_state(cx, || 1);
|
||||
|
||||
cx.render(rsx!(
|
||||
RenderG { seconds: seconds }
|
||||
|
||||
@@ -28,8 +28,8 @@ If we used global state like use_context or fermi, we might be tempted to inject
|
||||
|
||||
```rust
|
||||
fn Titlebar(cx: Scope<TitlebarProps>) -> Element {
|
||||
let title = use_read(&cx, TITLE);
|
||||
let subtitle = use_read(&cx, SUBTITLE);
|
||||
let title = use_read(cx, TITLE);
|
||||
let subtitle = use_read(cx, SUBTITLE);
|
||||
|
||||
cx.render(rsx!{/* ui */})
|
||||
}
|
||||
@@ -43,11 +43,11 @@ To enable our titlebar component to be used across apps, we want to lift our ato
|
||||
|
||||
```rust
|
||||
fn DocsiteTitlesection(cx: Scope) {
|
||||
let title = use_read(&cx, TITLE);
|
||||
let subtitle = use_read(&cx, SUBTITLE);
|
||||
let title = use_read(cx, TITLE);
|
||||
let subtitle = use_read(cx, SUBTITLE);
|
||||
|
||||
let username = use_read(&cx, USERNAME);
|
||||
let points = use_read(&cx, POINTS);
|
||||
let username = use_read(cx, USERNAME);
|
||||
let points = use_read(cx, POINTS);
|
||||
|
||||
cx.render(rsx!{
|
||||
TitleBar { title: title, subtitle: subtitle }
|
||||
|
||||
@@ -13,7 +13,7 @@ struct Todo {
|
||||
is_editing: bool,
|
||||
}
|
||||
|
||||
let todos = use_ref(&cx, || vec![Todo::new()]);
|
||||
let todos = use_ref(cx, || vec![Todo::new()]);
|
||||
|
||||
cx.render(rsx!{
|
||||
ul {
|
||||
@@ -40,7 +40,7 @@ Instead, let's refactor our Todo component to handle its own state:
|
||||
```rust
|
||||
#[inline_props]
|
||||
fn Todo<'a>(cx: Scope, todo: &'a Todo) -> Element {
|
||||
let is_hovered = use_state(&cx, || false);
|
||||
let is_hovered = use_state(cx, || false);
|
||||
|
||||
cx.render(rsx!{
|
||||
li {
|
||||
@@ -80,15 +80,15 @@ struct State {
|
||||
}
|
||||
|
||||
// in the component
|
||||
let state = use_ref(&cx, State::new)
|
||||
let state = use_ref(cx, State::new)
|
||||
```
|
||||
|
||||
The "better" approach for this particular component would be to break the state apart into different values:
|
||||
|
||||
```rust
|
||||
let count = use_state(&cx, || 0);
|
||||
let color = use_state(&cx, || "red");
|
||||
let names = use_state(&cx, HashMap::new);
|
||||
let count = use_state(cx, || 0);
|
||||
let color = use_state(cx, || "red");
|
||||
let names = use_state(cx, HashMap::new);
|
||||
```
|
||||
|
||||
You might recognize that our "names" value is a HashMap – which is not terribly cheap to clone every time we update its value. To solve this issue, we *highly* suggest using a library like [`im`](https://crates.io/crates/im) which will take advantage of structural sharing to make clones and mutations much cheaper.
|
||||
@@ -96,7 +96,7 @@ You might recognize that our "names" value is a HashMap – which is not terribl
|
||||
When combined with the `make_mut` method on `use_state`, you can get really succinct updates to collections:
|
||||
|
||||
```rust
|
||||
let todos = use_state(&cx, im_rc::HashMap::default);
|
||||
let todos = use_state(cx, im_rc::HashMap::default);
|
||||
|
||||
todos.make_mut().insert("new todo", Todo {
|
||||
contents: "go get groceries",
|
||||
|
||||
@@ -8,8 +8,8 @@ For example, let's say we have a component that has two children:
|
||||
```rust
|
||||
fn Demo(cx: Scope) -> Element {
|
||||
// don't worry about these 2, we'll cover them later
|
||||
let name = use_state(&cx, || String::from("bob"));
|
||||
let age = use_state(&cx, || 21);
|
||||
let name = use_state(cx, || String::from("bob"));
|
||||
let age = use_state(cx, || 21);
|
||||
|
||||
cx.render(rsx!{
|
||||
Name { name: name }
|
||||
|
||||
@@ -20,7 +20,7 @@ Our component is really simple – we just call `use_ref` to get an initial calc
|
||||
|
||||
```rust
|
||||
fn app(cx: Scope) -> Element {
|
||||
let state = use_ref(&cx, Calculator::new);
|
||||
let state = use_ref(cx, Calculator::new);
|
||||
|
||||
cx.render(rsx!{
|
||||
// the rendering code
|
||||
|
||||
@@ -10,7 +10,7 @@ The basic setup for coroutines is the `use_coroutine` hook. Most coroutines we w
|
||||
|
||||
```rust
|
||||
fn app(cx: Scope) -> Element {
|
||||
let ws: &UseCoroutine<()> = use_coroutine(&cx, |rx| async move {
|
||||
let ws: &UseCoroutine<()> = use_coroutine(cx, |rx| async move {
|
||||
// Connect to some sort of service
|
||||
let mut conn = connect_to_ws_server().await;
|
||||
|
||||
@@ -27,7 +27,7 @@ For many services, a simple async loop will handle the majority of use cases.
|
||||
However, if we want to temporarily disable the coroutine, we can "pause" it using the `pause` method, and "resume" it using the `resume` method:
|
||||
|
||||
```rust
|
||||
let sync: &UseCoroutine<()> = use_coroutine(&cx, |rx| async move {
|
||||
let sync: &UseCoroutine<()> = use_coroutine(cx, |rx| async move {
|
||||
// code for syncing
|
||||
});
|
||||
|
||||
@@ -63,7 +63,7 @@ enum ProfileUpdate {
|
||||
SetAge(i32)
|
||||
}
|
||||
|
||||
let profile = use_coroutine(&cx, |mut rx: UnboundedReciver<ProfileUpdate>| async move {
|
||||
let profile = use_coroutine(cx, |mut rx: UnboundedReciver<ProfileUpdate>| async move {
|
||||
let mut server = connect_to_server().await;
|
||||
|
||||
while let Ok(msg) = rx.next().await {
|
||||
@@ -86,9 +86,9 @@ cx.render(rsx!{
|
||||
For sufficiently complex apps, we could build a bunch of different useful "services" that loop on channels to update the app.
|
||||
|
||||
```rust
|
||||
let profile = use_coroutine(&cx, profile_service);
|
||||
let editor = use_coroutine(&cx, editor_service);
|
||||
let sync = use_coroutine(&cx, sync_service);
|
||||
let profile = use_coroutine(cx, profile_service);
|
||||
let editor = use_coroutine(cx, editor_service);
|
||||
let sync = use_coroutine(cx, sync_service);
|
||||
|
||||
async fn profile_service(rx: UnboundedReceiver<ProfileCommand>) {
|
||||
// do stuff
|
||||
@@ -109,9 +109,9 @@ We can combine coroutines with Fermi to emulate Redux Toolkit's Thunk system wit
|
||||
static USERNAME: Atom<String> = |_| "default".to_string();
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let atoms = use_atom_root(&cx);
|
||||
let atoms = use_atom_root(cx);
|
||||
|
||||
use_coroutine(&cx, |rx| sync_service(rx, atoms.clone()));
|
||||
use_coroutine(cx, |rx| sync_service(rx, atoms.clone()));
|
||||
|
||||
cx.render(rsx!{
|
||||
Banner {}
|
||||
@@ -119,7 +119,7 @@ fn app(cx: Scope) -> Element {
|
||||
}
|
||||
|
||||
fn Banner(cx: Scope) -> Element {
|
||||
let username = use_read(&cx, USERNAME);
|
||||
let username = use_read(cx, USERNAME);
|
||||
|
||||
cx.render(rsx!{
|
||||
h1 { "Welcome back, {username}" }
|
||||
@@ -158,8 +158,8 @@ To yield values from a coroutine, simply bring in a `UseState` handle and set th
|
||||
|
||||
|
||||
```rust
|
||||
let sync_status = use_state(&cx, || Status::Launching);
|
||||
let sync_task = use_coroutine(&cx, |rx: UnboundedReceiver<SyncAction>| {
|
||||
let sync_status = use_state(cx, || Status::Launching);
|
||||
let sync_task = use_coroutine(cx, |rx: UnboundedReceiver<SyncAction>| {
|
||||
to_owned![sync_status];
|
||||
async move {
|
||||
loop {
|
||||
@@ -176,7 +176,7 @@ Coroutine handles are automatically injected through the context API. `use_corou
|
||||
|
||||
```rust
|
||||
fn Child(cx: Scope) -> Element {
|
||||
let sync_task = use_coroutine_handle::<SyncAction>(&cx);
|
||||
let sync_task = use_coroutine_handle::<SyncAction>(cx);
|
||||
|
||||
sync_task.send(SyncAction::SetUsername);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ The next "best" way of handling errors in Dioxus is to match on the error locall
|
||||
To do this, we simply have an error state built into our component:
|
||||
|
||||
```rust
|
||||
let err = use_state(&cx, || None);
|
||||
let err = use_state(cx, || None);
|
||||
```
|
||||
|
||||
Whenever we perform an action that generates an error, we'll set that error state. We can then match on the error in a number of ways (early return, return Element, etc).
|
||||
@@ -64,7 +64,7 @@ Whenever we perform an action that generates an error, we'll set that error stat
|
||||
|
||||
```rust
|
||||
fn Commandline(cx: Scope) -> Element {
|
||||
let error = use_state(&cx, || None);
|
||||
let error = use_state(cx, || None);
|
||||
|
||||
cx.render(match *error {
|
||||
Some(error) => rsx!(
|
||||
@@ -85,7 +85,7 @@ If you're dealing with a handful of components with minimal nesting, you can jus
|
||||
|
||||
```rust
|
||||
fn Commandline(cx: Scope) -> Element {
|
||||
let error = use_state(&cx, || None);
|
||||
let error = use_state(cx, || None);
|
||||
|
||||
if let Some(error) = **error {
|
||||
return cx.render(rsx!{ "An error occured" });
|
||||
@@ -125,7 +125,7 @@ Then, in our top level component, we want to explicitly handle the possible erro
|
||||
|
||||
```rust
|
||||
fn TopLevel(cx: Scope) -> Element {
|
||||
let error = use_read(&cx, INPUT_ERROR);
|
||||
let error = use_read(cx, INPUT_ERROR);
|
||||
|
||||
match error {
|
||||
TooLong => return cx.render(rsx!{ "FAILED: Too long!" }),
|
||||
@@ -139,7 +139,7 @@ Now, whenever a downstream component has an error in its actions, it can simply
|
||||
|
||||
```rust
|
||||
fn Commandline(cx: Scope) -> Element {
|
||||
let set_error = use_set(&cx, INPUT_ERROR);
|
||||
let set_error = use_set(cx, INPUT_ERROR);
|
||||
|
||||
cx.render(rsx!{
|
||||
input {
|
||||
|
||||
@@ -6,7 +6,7 @@ Dioxus is a portable, performant, and ergonomic framework for building cross-pla
|
||||
|
||||
```rust
|
||||
fn app(cx: Scope) -> Element {
|
||||
let mut count = use_state(&cx, || 0);
|
||||
let mut count = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx!(
|
||||
h1 { "High-Five counter: {count}" }
|
||||
@@ -48,4 +48,4 @@ Web: Since the web is a fairly mature platform, we expect there to be very littl
|
||||
|
||||
Desktop: APIs will likely be in flux as we figure out better patterns than our ElectronJS counterpart.
|
||||
|
||||
SSR: We don't expect the SSR API to change drastically in the future.
|
||||
SSR: We don't expect the SSR API to change drastically in the future.
|
||||
@@ -10,7 +10,7 @@ A configuração básica para corrotinas é o _hook_ `use_coroutine`. A maioria
|
||||
|
||||
```rust
|
||||
fn app(cx: Scope) -> Element {
|
||||
let ws: &UseCoroutine<()> = use_coroutine(&cx, |rx| async move {
|
||||
let ws: &UseCoroutine<()> = use_coroutine(cx, |rx| async move {
|
||||
// Connect to some sort of service
|
||||
let mut conn = connect_to_ws_server().await;
|
||||
|
||||
@@ -27,7 +27,7 @@ Para muitos serviços, um _loop_ assíncrono simples lidará com a maioria dos c
|
||||
No entanto, se quisermos desabilitar temporariamente a corrotina, podemos "pausá-la" usando o método `pause` e "retomá-la" usando o método `resume`:
|
||||
|
||||
```rust
|
||||
let sync: &UseCoroutine<()> = use_coroutine(&cx, |rx| async move {
|
||||
let sync: &UseCoroutine<()> = use_coroutine(cx, |rx| async move {
|
||||
// code for syncing
|
||||
});
|
||||
|
||||
@@ -62,7 +62,7 @@ enum ProfileUpdate {
|
||||
SetAge(i32)
|
||||
}
|
||||
|
||||
let profile = use_coroutine(&cx, |mut rx: UnboundedReciver<ProfileUpdate>| async move {
|
||||
let profile = use_coroutine(cx, |mut rx: UnboundedReciver<ProfileUpdate>| async move {
|
||||
let mut server = connect_to_server().await;
|
||||
|
||||
while let Ok(msg) = rx.next().await {
|
||||
@@ -85,9 +85,9 @@ cx.render(rsx!{
|
||||
Para aplicativos suficientemente complexos, poderíamos criar vários "serviços" úteis diferentes que fazem um _loop_ nos canais para atualizar o aplicativo.
|
||||
|
||||
```rust
|
||||
let profile = use_coroutine(&cx, profile_service);
|
||||
let editor = use_coroutine(&cx, editor_service);
|
||||
let sync = use_coroutine(&cx, sync_service);
|
||||
let profile = use_coroutine(cx, profile_service);
|
||||
let editor = use_coroutine(cx, editor_service);
|
||||
let sync = use_coroutine(cx, sync_service);
|
||||
|
||||
async fn profile_service(rx: UnboundedReceiver<ProfileCommand>) {
|
||||
// do stuff
|
||||
@@ -108,9 +108,9 @@ Podemos combinar corrotinas com `Fermi` para emular o sistema `Thunk` do **Redux
|
||||
static USERNAME: Atom<String> = |_| "default".to_string();
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let atoms = use_atom_root(&cx);
|
||||
let atoms = use_atom_root(cx);
|
||||
|
||||
use_coroutine(&cx, |rx| sync_service(rx, atoms.clone()));
|
||||
use_coroutine(cx, |rx| sync_service(rx, atoms.clone()));
|
||||
|
||||
cx.render(rsx!{
|
||||
Banner {}
|
||||
@@ -118,7 +118,7 @@ fn app(cx: Scope) -> Element {
|
||||
}
|
||||
|
||||
fn Banner(cx: Scope) -> Element {
|
||||
let username = use_read(&cx, USERNAME);
|
||||
let username = use_read(cx, USERNAME);
|
||||
|
||||
cx.render(rsx!{
|
||||
h1 { "Welcome back, {username}" }
|
||||
@@ -156,8 +156,8 @@ async fn sync_service(mut rx: UnboundedReceiver<SyncAction>, atoms: AtomRoot) {
|
||||
Para obter valores de uma corrotina, basta usar um identificador `UseState` e definir o valor sempre que sua corrotina concluir seu trabalho.
|
||||
|
||||
```rust
|
||||
let sync_status = use_state(&cx, || Status::Launching);
|
||||
let sync_task = use_coroutine(&cx, |rx: UnboundedReceiver<SyncAction>| {
|
||||
let sync_status = use_state(cx, || Status::Launching);
|
||||
let sync_task = use_coroutine(cx, |rx: UnboundedReceiver<SyncAction>| {
|
||||
to_owned![sync_status];
|
||||
async move {
|
||||
loop {
|
||||
@@ -174,7 +174,7 @@ Os identificadores de corrotina são injetados automaticamente por meio da API d
|
||||
|
||||
```rust
|
||||
fn Child(cx: Scope) -> Element {
|
||||
let sync_task = use_coroutine_handle::<SyncAction>(&cx);
|
||||
let sync_task = use_coroutine_handle::<SyncAction>(cx);
|
||||
|
||||
sync_task.send(SyncAction::SetUsername);
|
||||
}
|
||||
|
||||
@@ -53,14 +53,14 @@ A próxima "melhor" maneira de lidar com erros no Dioxus é combinar (`match`) o
|
||||
Para fazer isso, simplesmente temos um estado de erro embutido em nosso componente:
|
||||
|
||||
```rust
|
||||
let err = use_state(&cx, || None);
|
||||
let err = use_state(cx, || None);
|
||||
```
|
||||
|
||||
Sempre que realizarmos uma ação que gere um erro, definiremos esse estado de erro. Podemos então combinar o erro de várias maneiras (retorno antecipado, elemento de retorno etc.).
|
||||
|
||||
```rust
|
||||
fn Commandline(cx: Scope) -> Element {
|
||||
let error = use_state(&cx, || None);
|
||||
let error = use_state(cx, || None);
|
||||
|
||||
cx.render(match *error {
|
||||
Some(error) => rsx!(
|
||||
@@ -81,7 +81,7 @@ Se você estiver lidando com alguns componentes com um mínimo de aninhamento, b
|
||||
|
||||
```rust
|
||||
fn Commandline(cx: Scope) -> Element {
|
||||
let error = use_state(&cx, || None);
|
||||
let error = use_state(cx, || None);
|
||||
|
||||
if let Some(error) = **error {
|
||||
return cx.render(rsx!{ "An error occured" });
|
||||
@@ -120,7 +120,7 @@ Então, em nosso componente de nível superior, queremos tratar explicitamente o
|
||||
|
||||
```rust
|
||||
fn TopLevel(cx: Scope) -> Element {
|
||||
let error = use_read(&cx, INPUT_ERROR);
|
||||
let error = use_read(cx, INPUT_ERROR);
|
||||
|
||||
match error {
|
||||
TooLong => return cx.render(rsx!{ "FAILED: Too long!" }),
|
||||
@@ -134,7 +134,7 @@ Agora, sempre que um componente _downstream_ tiver um erro em suas ações, ele
|
||||
|
||||
```rust
|
||||
fn Commandline(cx: Scope) -> Element {
|
||||
let set_error = use_set(&cx, INPUT_ERROR);
|
||||
let set_error = use_set(cx, INPUT_ERROR);
|
||||
|
||||
cx.render(rsx!{
|
||||
input {
|
||||
|
||||
@@ -6,7 +6,7 @@ Dioxus é uma estrutura portátil, de alto desempenho e ergonômica para a const
|
||||
|
||||
```rust
|
||||
fn app(cx: Scope) -> Element {
|
||||
let mut count = use_state(&cx, || 0);
|
||||
let mut count = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx!(
|
||||
h1 { "High-Five counter: {count}" }
|
||||
|
||||
@@ -27,7 +27,7 @@ Dioxus is a recently-released library for building interactive user interfaces (
|
||||
|
||||
```rust
|
||||
fn app(cx: Scope) -> Element {
|
||||
let mut count = use_state(&cx, || 0);
|
||||
let mut count = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx! {
|
||||
h1 { "Count: {count}" }
|
||||
@@ -102,8 +102,8 @@ We're also using hooks to parse the URL parameters and segments so you can inter
|
||||
struct Query { name: String }
|
||||
|
||||
fn BlogPost(cx: Scope) -> Element {
|
||||
let post = use_route(&cx).segment("post")?;
|
||||
let query = use_route(&cx).query::<Query>()?;
|
||||
let post = use_route(cx).segment("post")?;
|
||||
let query = use_route(cx).query::<Query>()?;
|
||||
|
||||
cx.render(rsx!{
|
||||
"Viewing post {post}"
|
||||
@@ -128,7 +128,7 @@ static TITLE: Atom<&str> = |_| "Hello";
|
||||
|
||||
// Read the value from anywhere in the app, subscribing to any changes
|
||||
fn app(cx: Scope) -> Element {
|
||||
let title = use_read(&cx, TITLE);
|
||||
let title = use_read(cx, TITLE);
|
||||
cx.render(rsx!{
|
||||
h1 { "{title}" }
|
||||
Child {}
|
||||
@@ -137,7 +137,7 @@ fn app(cx: Scope) -> Element {
|
||||
|
||||
// Set the value from anywhere in the app
|
||||
fn Child(cx: Scope) -> Element {
|
||||
let set_title = use_set(&cx, TITLE);
|
||||
let set_title = use_set(cx, TITLE);
|
||||
cx.render(rsx!{
|
||||
button {
|
||||
onclick: move |_| set_title("goodbye"),
|
||||
@@ -245,7 +245,7 @@ First, we upgraded the `use_future` hook. It now supports dependencies, which le
|
||||
|
||||
```rust
|
||||
fn RenderDog(cx: Scope, breed: String) -> Element {
|
||||
let dog_request = use_future(&cx, (breed,), |(breed,)| async move {
|
||||
let dog_request = use_future(cx, (breed,), |(breed,)| async move {
|
||||
reqwest::get(format!("https://dog.ceo/api/breed/{}/images/random", breed))
|
||||
.await
|
||||
.unwrap()
|
||||
@@ -265,7 +265,7 @@ Additionally, we added better support for coroutines. You can now start, stop, r
|
||||
|
||||
```rust
|
||||
fn App(cx: Scope) -> Element {
|
||||
let sync_task = use_coroutine(&cx, |rx| async move {
|
||||
let sync_task = use_coroutine(cx, |rx| async move {
|
||||
connect_to_server().await;
|
||||
let state = MyState::new();
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let mut count = use_state(&cx, || 0);
|
||||
let mut count = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx! {
|
||||
h1 { "Count: {count}" }
|
||||
@@ -138,7 +138,7 @@ struct CardProps {
|
||||
}
|
||||
|
||||
static Card: Component<CardProps> = |cx| {
|
||||
let mut count = use_state(&cx, || 0);
|
||||
let mut count = use_state(cx, || 0);
|
||||
cx.render(rsx!(
|
||||
aside {
|
||||
h2 { "{cx.props.title}" }
|
||||
@@ -191,7 +191,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let mut count = use_state(&cx, || 0);
|
||||
let mut count = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx! {
|
||||
h1 { "Count: {count}" }
|
||||
@@ -260,7 +260,7 @@ Dioxus understands the lifetimes of data borrowed from `Scope`, so you can safel
|
||||
|
||||
|
||||
```rust
|
||||
let name = use_state(&cx, || "asd");
|
||||
let name = use_state(cx, || "asd");
|
||||
rsx! {
|
||||
div {
|
||||
button { onclick: move |_| name.set("abc") }
|
||||
@@ -274,7 +274,7 @@ Because we know the lifetime of your handlers, we can also expose this to childr
|
||||
|
||||
```rust
|
||||
fn app(cx: Scope) -> Element {
|
||||
let name = use_state(&cx, || "asd");
|
||||
let name = use_state(cx, || "asd");
|
||||
cx.render(rsx!{
|
||||
Button { name: name }
|
||||
})
|
||||
|
||||
@@ -10,12 +10,12 @@ Let's create a new ``navbar`` component:
|
||||
fn navbar(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
ul {
|
||||
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
Our navbar will be a list of links going between our pages. We could always use an HTML anchor element but that would cause our page to unnecessarily reload. Instead we want to use the ``Link`` component provided by Dioxus Router.
|
||||
Our navbar will be a list of links going between our pages. We could always use an HTML anchor element but that would cause our page to unnecessarily reload. Instead we want to use the ``Link`` component provided by Dioxus Router.
|
||||
|
||||
The Link component is very similar to the Route component. It takes a path and an element. Add the Link component into your use statement and then add some links:
|
||||
```rs
|
||||
@@ -38,7 +38,7 @@ fn navbar(cx: Scope) -> Element {
|
||||
}
|
||||
```
|
||||
>By default, the Link component only works for links within your application. To link to external sites, add the ``external: true`` property.
|
||||
>```rs
|
||||
>```rs
|
||||
>Link { to: "https://github.com", external: true, "GitHub"}
|
||||
>```
|
||||
|
||||
@@ -66,7 +66,7 @@ We want to store our blogs in a database and load them as needed. This'll help p
|
||||
We could utilize a search page that loads a blog when clicked but then our users won't be able to share our blogs easily. This is where URL parameters come in. And finally, we also want our site to tell users they are on a blog page whenever the URL starts with``/blog``.
|
||||
|
||||
The path to our blog will look like ``/blog/myBlogPage``. ``myBlogPage`` being the URL parameter.
|
||||
Dioxus Router uses the ``:name`` pattern so our route will look like ``/blog/:post``.
|
||||
Dioxus Router uses the ``:name`` pattern so our route will look like ``/blog/:post``.
|
||||
|
||||
First, lets tell users when they are on a blog page. Add a new route in your app component.
|
||||
```rs
|
||||
@@ -77,7 +77,7 @@ fn app(cx: Scope) -> Element {
|
||||
self::navbar {}
|
||||
Route { to: "/", self::homepage {}}
|
||||
// NEW
|
||||
Route {
|
||||
Route {
|
||||
to: "/blog",
|
||||
}
|
||||
Route { to: "", self::page_not_found {}}
|
||||
@@ -93,7 +93,7 @@ fn app(cx: Scope) -> Element {
|
||||
p { "-- Dioxus Blog --" }
|
||||
self::navbar {}
|
||||
Route { to: "/", self::homepage {}}
|
||||
Route {
|
||||
Route {
|
||||
to: "/blog",
|
||||
Route { to: "/:post", "This is my blog post!" } // NEW
|
||||
}
|
||||
@@ -109,7 +109,7 @@ fn app(cx: Scope) -> Element {
|
||||
Router {
|
||||
self::navbar {}
|
||||
Route { to: "/", self::homepage {}}
|
||||
Route {
|
||||
Route {
|
||||
to: "/blog",
|
||||
p { "-- Dioxus Blog --" } // MOVED
|
||||
Route { to: "/:post", "This is my blog post!" }
|
||||
@@ -119,7 +119,7 @@ fn app(cx: Scope) -> Element {
|
||||
})
|
||||
}
|
||||
```
|
||||
Now our ``-- Dioxus Blog --`` text will be displayed whenever a user is on a path that starts with ``/blog``. Displaying content in a way that is page-agnostic is useful when building navigation menus, footers, and similar.
|
||||
Now our ``-- Dioxus Blog --`` text will be displayed whenever a user is on a path that starts with ``/blog``. Displaying content in a way that is page-agnostic is useful when building navigation menus, footers, and similar.
|
||||
|
||||
All that's left is to handle our URL parameter. We will begin by creating a ``get_blog_post`` function. In a real site, this function would call an API endpoint to get a blog post from the database. However, that is out of the scope of this guide so we will be utilizing static text.
|
||||
```rs
|
||||
@@ -153,7 +153,7 @@ use dioxus::{
|
||||
...
|
||||
|
||||
fn blog_post(cx: Scope) -> Element {
|
||||
let route = use_route(&cx); // NEW
|
||||
let route = use_route(cx); // NEW
|
||||
let blog_text = "";
|
||||
|
||||
cx.render(rsx! {
|
||||
@@ -165,7 +165,7 @@ Dioxus Router provides built in methods to extract information from a route. We
|
||||
The ``segment`` method also parses the parameter into any type for us. We'll use a match expression that handles a parsing error and on success, uses our helper function to grab the blog post.
|
||||
```rs
|
||||
fn blog_post(cx: Scope) -> Element {
|
||||
let route = use_route(&cx);
|
||||
let route = use_route(cx);
|
||||
|
||||
// NEW
|
||||
let blog_text = match route.segment::<String>("post").unwrap() {
|
||||
@@ -198,4 +198,4 @@ fn app(cx: Scope) -> Element {
|
||||
That's it! If you head to ``/blog/foo`` you should see ``Welcome to the foo blog post!``.
|
||||
|
||||
### Conclusion
|
||||
In this chapter we utilized Dioxus Router's Link, URL Parameter, and ``use_route`` functionality to build the blog portion of our application. In the next and final chapter, we will go over the ``Redirect`` component to redirect non-authorized users to another page.
|
||||
In this chapter we utilized Dioxus Router's Link, URL Parameter, and ``use_route`` functionality to build the blog portion of our application. In the next and final chapter, we will go over the ``Redirect`` component to redirect non-authorized users to another page.
|
||||
Reference in new issue
Block a user