Add PT-BR translations (#456)

* Translate final.md, hello_world.md, README.md, ROADMAP.md and SUMMARY.md

* Translatation complete

* Internationalization: move guide to en folder and preserve its history. (#494)

* Clean files and build mdBook with localization feature

* Rebase, remove leftovers and check book builds for every language: ✅

Co-authored-by: Jon Kelley <jkelleyrtp@gmail.com>
This commit is contained in:
Breno RochaandJon Kelley authored and GitHub committed 2022-07-11 13:28:12 -04:00
1 parent 2369b0cc7f
commit 6ea076fa7f
69 files changed
+4239 -13

No files matched your search

+25
View File
@@ -0,0 +1,25 @@
# Dioxus: Guias Avançados e Referência
![dioxuslogo](./images/dioxuslogo_full.png)
**Dioxus** é um framework e ecossistema para desenvolver interfaces rápidas, escaláveis e robustas com a linguagem de Programação Rust. Este guia irá ajudar você a começar com o Dioxus para Web, Desktop, Móvel e mais.
> Este livro é a Referência e Guias Avançados para o framework Dioxus. Para um tutorial em como de fato _usar_ o Dioxus, procure o [guia oficial](https://dioxuslabs.com/guide/).
## Guias e Referência
Com a referência nós procuramos manter a documentar a funcionalidade que pode não ter sido mencionada no guia oficial para manter uma carga de informação mínima. Alguns tópicos não estão inclusos pelo guia, mas discutidos nesta referência incluindo:
- Processo seguro (`ThreadSafe`) da `VirtualDOM`
- Abordagem complete sobre o uso do `rsx!` e funções inclusas
- Padrão `spread` para as propriedades dos componentes
- Testes
- Memoization à fundo
- Elementos personalizados
- Renderizadores personalizados
## Contribuindo
Se nesse documento estiver de algum forma confuso, contém erros de digitação ou você gostaria de ajudar a melhorar algo, sinta-se à vontade para fazer um PR no [repositório do Dioxus](https://github.com/DioxusLabs/dioxus/tree/master/docs/reference).
Todas as contribuições serão licenciadas sob a licença MIT/Apache2.
+47
View File
@@ -0,0 +1,47 @@
# Summary
- [Introdução](README.md)
- [Platformas](platforms/index.md)
- [Web](platforms/web.md)
- [Renderização por Servidor(SSR)](platforms/ssr.md)
- [Desktop](platforms/desktop.md)
- [Móvel](platforms/mobile.md)
- [TUI](platforms/tui.md)
- [Guias Avançados](guide/index.md)
- [RSX à fundo](guide/rsx_in_depth.md)
- [Componentes](guide/components.md)
- [Propriedades](guide/props.md)
- [Memoization](guide/memoization.md)
- [Desempenho](guide/performance.md)
- [Testes](guide/testing.md)
- [Construindo Elementos com o NodeFactory](guide/rsx.md)
- [Elementos Personalizados](guide/custom_elements.md)
- [Renderizadores Personalizados](guide/custom_renderer.md)
- [Componentes Renderizados por Servidor](guide/server_side_components.md)
- [Empacotando e Distribuindo](guide/bundline.md)
- [Recarregamento em Tempo-Real com RSX](guide/hot_reloading.md)
- [Guia de Referência](reference/reference.md)
- [Anti-padrões](reference/anti.md)
- [Filhos](reference/children.md)
- [Renderização Condicional](reference/conditional.md)
- [Entradas Controladas](reference/controlled.md)
- [Elementos Personalizados](reference/custom.md)
- [Componentes Vazios](reference/empty.md)
- [Tratamento de Errors](reference/error.md)
- [Fragmentos](reference/fragments.md)
- [CSS Globais](reference/global.md)
- [Estilos em Linha](reference/inline.md)
- [Iteradores](reference/iterators.md)
- [Ouvintes](reference/listeners.md)
- [Memoization](reference/memoization.md)
- [Nós de Referência](reference/node.md)
- [Padrão Propagado (Spread)](reference/spread.md)
- [Gerenciamento de Estado](reference/state.md)
- [Suspensão](reference/suspense.md)
- [Tarefas](reference/task.md)
- [Testes](reference/testing.md)
@@ -0,0 +1,497 @@
# Renderizador Personalizado
Dioxus é uma estrutura incrivelmente portátil para desenvolvimento de interface do usuário. As lições, conhecimentos, hooks e componentes que você adquire ao longo do tempo sempre podem ser aproveitados ​​para projetos futuros. No entanto, às vezes, esses projetos não podem aproveitar um renderizador compatível ou você precisa implementar seu próprio renderizador melhor.
Ótimas notícias: o design do renderizador depende inteiramente de você! Nós fornecemos sugestões e inspiração com os renderizadores originais, mas só realmente precisamos processar `DomEdits` e enviar `UserEvents`.
## Em Detalhes:
A implementação do renderizador é bastante simples. O renderizador precisa:
1. Lidar com o fluxo de edições gerado por atualizações no DOM virtual
2. Registrar ouvintes e passe eventos para o sistema de eventos do DOM virtual
Essencialmente, seu renderizador precisa implementar o traço `RealDom` e gerar objetos `EventTrigger` para atualizar o `VirtualDOM`. A partir daí, você terá tudo o que precisa para renderizar o `VirtualDOM` na tela.
Internamente, o Dioxus lida com o relacionamento da árvore, `diffing`, gerenciamento de memória e o sistema de eventos, deixando o mínimo necessário para que os renderizadores se implementem.
Para referência, confira o interpretador JavaScript ou o renderizador TUI como ponto de partida para seu renderizador personalizado.
## DomEdições
O tipo "DomEdit" é uma enumeração serializada que representa uma operação atômica que ocorre no `RealDom`. As variantes seguem aproximadamente este conjunto:
```rust
enum DomEdit {
PushRoot,
AppendChildren,
ReplaceWith,
InsertAfter,
InsertBefore,
Remove,
CreateTextNode,
CreateElement,
CreateElementNs,
CreatePlaceholder,
NewEventListener,
RemoveEventListener,
SetText,
SetAttribute,
RemoveAttribute,
PopRoot,
}
```
O mecanismo de diferenciação do Dioxus opera como uma [máquina de pilha] (https://en.wikipedia.org/wiki/Stack_machine) onde o método `push_root` empilhar um novo nó DOM "real" para a pilha e `append_child` e `replace_with` ambos removem nós da pilha.
### Um exemplo
Por uma questão de compreensão, vamos considerar este exemplo - uma declaração de interface do usuário muito simples:
```rust
rsx!( h1 {"hello world"} )
```
To get things started, Dioxus must first navigate to the container of this h1 tag. To "navigate" here, the internal diffing algorithm generates the DomEdit `PushRoot` where the ID of the root is the container.
When the renderer receives this instruction, it pushes the actual Node onto its own stack. The real renderer's stack will look like this:
```rust
instructions: [
PushRoot(Container)
]
stack: [
ContainerNode,
]
```
Em seguida, o Dioxus encontrará o nó `h1`. O algoritmo `diff` decide que este nó precisa ser criado, então o Dioxus irá gerar o DomEdit `CreateElement`. Quando o renderizador receber esta instrução, ele criará um nó desmontado e o enviará para sua própria pilha:
```rust
instructions: [
PushRoot(Container),
CreateElement(h1),
]
stack: [
ContainerNode,
h1,
]
```
Em seguida, Dioxus vê o nó de texto e gera o DomEdit `CreateTextNode`:
```rust
instructions: [
PushRoot(Container),
CreateElement(h1),
CreateTextNode("hello world")
]
stack: [
ContainerNode,
h1,
"hello world"
]
```
Lembre-se, o nó de texto não está anexado a nada (ele está desmontado), então o Dioxus precisa gerar um `Edit` que conecte o nó de texto ao elemento `h1`. Depende da situação, mas neste caso usamos `AppendChildren`. Isso remove o nó de texto da pilha, deixando o elemento `h1` como o próximo elemento na linha.
```rust
instructions: [
PushRoot(Container),
CreateElement(h1),
CreateTextNode("hello world"),
AppendChildren(1)
]
stack: [
ContainerNode,
h1
]
```
Chamamos `AppendChildren` novamente, retirando o nó `h1` e anexando-o ao pai:
```rust
instructions: [
PushRoot(Container),
CreateElement(h1),
CreateTextNode("hello world"),
AppendChildren(1),
AppendChildren(1)
]
stack: [
ContainerNode,
]
```
Finalmente, o contêiner é aberto, pois não precisamos mais dele.
```rust
instructions: [
PushRoot(Container),
CreateElement(h1),
CreateTextNode("hello world"),
AppendChildren(1),
AppendChildren(1),
PopRoot
]
stack: []
```
Com o tempo, nossa pilha ficou assim:
```rust
[]
[Container]
[Container, h1]
[Container, h1, "hello world"]
[Container, h1]
[Container]
[]
```
Observe como nossa pilha fica vazia depois que a interface do usuário é montada. Convenientemente, essa abordagem separa completamente o `VirtualDOM` e o `RealDOM`. Além disso, essas edições são serializáveis, o que significa que podemos até gerenciar UIs em uma conexão de rede. Esta pequena máquina de pilha e edições serializadas tornam o Dioxus independente das especificidades da plataforma.
Dioxus também é muito rápido. Como o Dioxus divide a fase de `diff` e `patch`, ele é capaz de fazer todas as edições no `RealDOM` em um período de tempo muito curto (menos de um único quadro), tornando a renderização muito rápida. Ele também permite que o Dioxus cancele grandes operações de diferenciação se ocorrer um trabalho de prioridade mais alta durante a diferenciação.
É importante notar que há uma camada de conexão entre o Dioxus e o renderizador. O Dioxus salva e carrega elementos (a edição `PushRoot`) com um ID. Dentro do `VirtualDOM`, isso é rastreado apenas como um `u64`.
Sempre que uma edição `CreateElement` é gerada durante a comparação, o Dioxus incrementa seu contador de nós e atribui a esse novo elemento seu `NodeCount` atual. O `RealDom` é responsável por lembrar este ID e enviar o nó correto quando `PushRoot(ID)` é gerado. Dioxus recupera os IDs de elementos quando removidos. Para ficar em sincronia com Dioxus, você pode usar um `Sparce Vec` (`Vec<Option<T>>`) com itens possivelmente desocupados. Você pode usar os ids como índices no `Vec` para elementos e aumentar o `Vec` quando um id não existir.
Esta pequena demonstração serve para mostrar exatamente como um renderizador precisaria processar um stream de edição para construir UIs. Um conjunto de DOMEdits serializados para várias demos está disponível para você testar seu renderizador personalizado.
## Ciclo de eventos
Como a maioria das GUIs, o Dioxus conta com um `loop` de eventos para progredir no `VirtualDOM`. O próprio `VirtualDOM` também pode produzir eventos, por isso é importante que seu renderizador personalizado também possa lidar com eles.
O código para a implementação do `WebSys` é direto, então vamos adicioná-lo aqui para demonstrar como um `loop` de eventos é simples:
```rust
pub async fn run(&mut self) -> dioxus_core::error::Result<()> {
// Push the body element onto the WebsysDom's stack machine
let mut websys_dom = crate::new::WebsysDom::new(prepare_websys_dom());
websys_dom.stack.push(root_node);
// Rebuild or hydrate the virtualdom
let mutations = self.internal_dom.rebuild();
websys_dom.apply_mutations(mutations);
// Wait for updates from the real dom and progress the virtual dom
loop {
let user_input_future = websys_dom.wait_for_event();
let internal_event_future = self.internal_dom.wait_for_work();
match select(user_input_future, internal_event_future).await {
Either::Left((_, _)) => {
let mutations = self.internal_dom.work_with_deadline(|| false);
websys_dom.apply_mutations(mutations);
},
Either::Right((event, _)) => websys_dom.handle_event(event),
}
// render
}
}
```
É importante que você decodifique os eventos reais do seu sistema de eventos no sistema de eventos sintético do Dioxus (significado sintético abstraído). Isso significa simplesmente combinar seu tipo de evento e criar um tipo Dioxus `UserEvent`. No momento, o sistema `VirtualEvent` é modelado quase inteiramente em torno da especificação HTML, mas estamos interessados em reduzi-lo.
```rust
fn virtual_event_from_websys_event(event: &web_sys::Event) -> VirtualEvent {
match event.type_().as_str() {
"keydown" => {
let event: web_sys::KeyboardEvent = event.clone().dyn_into().unwrap();
UserEvent::KeyboardEvent(UserEvent {
scope_id: None,
priority: EventPriority::Medium,
name: "keydown",
// This should be whatever element is focused
element: Some(ElementId(0)),
data: Arc::new(KeyboardData{
char_code: event.char_code(),
key: event.key(),
key_code: event.key_code(),
alt_key: event.alt_key(),
ctrl_key: event.ctrl_key(),
meta_key: event.meta_key(),
shift_key: event.shift_key(),
locale: "".to_string(),
location: event.location(),
repeat: event.repeat(),
which: event.which(),
})
})
}
_ => todo!()
}
}
```
## Elementos brutos personalizados
Se você precisar ir mais longe a ponto de confiar em elementos personalizados para o seu renderizador - você pode. Isso ainda permitiria que você usasse a natureza reativa do Dioxus, sistema de componentes, estado compartilhado e outros recursos, mas acabará gerando nós diferentes. Todos os atributos e ouvintes para o namespace HTML e SVG são transportados por meio de estruturas auxiliares que essencialmente compilam (não representam sobrecarga de tempo de execução). Você pode colocar seus próprios elementos a qualquer hora que quiser, sem problemas. No entanto, você deve ter certeza absoluta de que seu renderizador pode lidar com o novo tipo, ou ele irá "bater e queimar".
Esses elementos personalizados são definidos como `unit struct` com implementações de `traits`.
Por exemplo, o elemento `div` é (aproximadamente!) definido assim:
```rust
struct div;
impl div {
/// Some glorious documentation about the class property.
const TAG_NAME: &'static str = "div";
const NAME_SPACE: Option<&'static str> = None;
// define the class attribute
pub fn class<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
cx.attr("class", val, None, false)
}
// more attributes
}
```
Você provavelmente notou que muitos elementos nas macros `rsx!` suportam documentação em foco. A abordagem que adotamos para elementos personalizados significa que a estrutura da unidade é criada imediatamente onde o elemento é usado no macro. Quando o macro é expandido, os comentários doc ainda se aplicam à estrutura da unidade, dando toneladas de feedback no editor, mesmo dentro de uma macro procedural.
# Núcleo Nativo
Os renderizadores dão muito trabalho. Se você estiver criando um renderizador em Rust, o núcleo nativo fornece alguns utilitários para implementar um renderizador. Ele fornece uma abstração sobre DomEdits e manipula o layout para você.
## RealDom
O `RealDom` é uma abstração de nível superior sobre a atualização do DOM. Ele é atualizado com `DomEdits` e fornece uma maneira de atualizar lentamente o estado dos nós com base em quais atributos mudam.
### Exemplo
Vamos construir um renderizador de brinquedo com bordas, tamanho e cor do texto.
Antes de começarmos, vamos dar uma olhada em um elemento de exemplo que podemos renderizar:
```rust
cx.render(rsx!{
div{
color: "red",
p{
border: "1px solid black",
"hello world"
}
}
})
```
Nesta árvore a cor depende da cor do pai. O tamanho depende do tamanho das crianças, do texto atual e do tamanho do texto. A borda depende apenas do nó atual.
```mermaid
flowchart TB
subgraph context
text_width(text width)
end
subgraph div
state1(state)-->color1(color)
state1(state)-->border1(border)
border1-.->text_width
linkStyle 2 stroke:#5555ff,stroke-width:4px;
state1(state)-->layout_width1(layout width)
end
subgraph p
state2(state)-->color2(color)
color2-.->color1(color)
linkStyle 5 stroke:#0000ff,stroke-width:4px;
state2(state)-->border2(border)
border2-.->text_width
linkStyle 7 stroke:#5555ff,stroke-width:4px;
state2(state)-->layout_width2(layout width)
layout_width1-.->layout_width2
linkStyle 9 stroke:#aaaaff,stroke-width:4px;
end
subgraph hello world
state3(state)-->color3(color)
color3-.->color2(color)
linkStyle 11 stroke:#0000ff,stroke-width:4px;
state3(state)-->border3(border)
border3-.->text_width
linkStyle 13 stroke:#5555ff,stroke-width:4px;
state3(state)-->layout_width3(layout width)
layout_width2-.->layout_width3
linkStyle 15 stroke:#aaaaff,stroke-width:4px;
end
```
Para ajudar na construção de um Dom, o núcleo nativo fornece quatro características: `State`, `ChildDepState`, `ParentDepState` e `NodeDepState` e uma estrutura `RealDom`.
```rust
use dioxus_native_core::node_ref::*;
use dioxus_native_core::state::{ChildDepState, NodeDepState, ParentDepState, State};
use dioxus_native_core_macro::{sorted_str_slice, State};
#[derive(Default, Copy, Clone)]
struct Size(f32, f32);
// Size only depends on the current node and its children, so it implements ChildDepState
impl ChildDepState for Size {
// Size accepts a font size context
type Ctx = f32;
// Size depends on the Size part of each child
type DepState = Self;
// Size only cares about the width, height, and text parts of the current node
const NODE_MASK: NodeMask =
NodeMask::new_with_attrs(AttributeMask::Static(&sorted_str_slice!(["width", "height"]))).with_text();
fn reduce<'a>(
&mut self,
node: NodeView,
children: impl Iterator<Item = &'a Self::DepState>,
ctx: &Self::Ctx,
) -> bool
where
Self::DepState: 'a,
{
let mut width;
let mut height;
if let Some(text) = node.text() {
// if the node has text, use the text to size our object
width = text.len() as f32 * ctx;
height = ctx;
} else {
// otherwise, the size is the maximum size of the children
width = *children
.reduce(|accum, item| if accum >= item.0 { accum } else { item.0 })
.unwrap_or(0.0));
height = *children
.reduce(|accum, item| if accum >= item.1 { accum } else { item.1 })
.unwrap_or(&0.0);
}
// if the node contains a width or height attribute it overrides the other size
for a in node.attibutes(){
match a.name{
"width" => width = a.value.parse().unwrap(),
"height" => height = a.value.parse().unwrap(),
// because Size only depends on the width and height, no other attributes will be passed to the member
_ => panic!()
}
}
// to determine what other parts of the dom need to be updated we return a boolean that marks if this member changed
let changed = (width != self.0) || (height != self.1);
*self = Self(width, height);
changed
}
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
struct TextColor {
r: u8,
g: u8,
b: u8,
}
// TextColor only depends on the current node and its parent, so it implements ParentDepState
impl ParentDepState for TextColor {
type Ctx = ();
// TextColor depends on the TextColor part of the parent
type DepState = Self;
// TextColor only cares about the color attribute of the current node
const NODE_MASK: NodeMask = NodeMask::new_with_attrs(AttributeMask::Static(&["color"]));
fn reduce(
&mut self,
node: NodeView,
parent: Option<&Self::DepState>,
_ctx: &Self::Ctx,
) -> bool {
// TextColor only depends on the color tag, so getting the first tag is equivilent to looking through all tags
let new = match node.attributes().next() {
// if there is a color tag, translate it
Some("red") => TextColor { r: 255, g: 0, b: 0 },
Some("green") => TextColor { r: 0, g: 255, b: 0 },
Some("blue") => TextColor { r: 0, g: 0, b: 255 },
Some(_) => panic!("unknown color"),
// otherwise check if the node has a parent and inherit that color
None => match parent {
Some(parent) => *parent,
None => Self::default(),
},
};
// check if the member has changed
let changed = new != *self;
*self = new;
changed
}
}
#[derive(Debug, Clone, PartialEq, Default)]
struct Border(bool);
// TextColor only depends on the current node, so it implements NodeDepState
impl NodeDepState for Border {
type Ctx = ();
// Border does not depended on any other member in the current node
type DepState = ();
// Border does not depended on any other member in the current node
const NODE_MASK: NodeMask =
NodeMask::new_with_attrs(AttributeMask::Static(&["border"]));
fn reduce(&mut self, node: NodeView, _sibling: &Self::DepState, _ctx: &Self::Ctx) -> bool {
// check if the node contians a border attribute
let new = Self(node.attributes().next().map(|a| a.name == "border").is_some());
// check if the member has changed
let changed = new != *self;
*self = new;
changed
}
}
// State provides a derive macro, but anotations on the members are needed in the form #[dep_type(dep_member, CtxType)]
#[derive(State, Default, Clone)]
struct ToyState {
// the color member of it's parent and no context
#[parent_dep_state(color)]
color: TextColor,
// depends on the node, and no context
#[node_dep_state()]
border: Border,
// depends on the layout_width member of children and f32 context (for text size)
#[child_dep_state(size, f32)]
size: Size,
}
```
Agora que temos nosso estado, podemos colocá-lo em uso em nosso DOM. Nós podemos atualizar o DOM com `update_state` para atualizar a estrutura do `DOM` (adicionando, removendo e alterando as propriedades dos nós) e então `apply_mutations` para atualizar o `ToyState` para cada um dos nós que foram alterados.
```rust
fn main(){
fn app(cx: Scope) -> Element {
cx.render(rsx!{
div{
color: "red",
"hello world"
}
})
}
let vdom = VirtualDom::new(app);
let rdom: RealDom<ToyState> = RealDom::new();
let mutations = dom.rebuild();
// update the structure of the real_dom tree
let to_update = rdom.apply_mutations(vec![mutations]);
let mut ctx = AnyMap::new();
// set the font size to 3.3
ctx.insert(3.3);
// update the ToyState for nodes in the real_dom tree
let _to_rerender = rdom.update_state(&dom, to_update, ctx).unwrap();
// we need to run the vdom in a async runtime
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()?
.block_on(async {
loop{
let wait = vdom.wait_for_work();
let mutations = vdom.work_with_deadline(|| false);
let to_update = rdom.apply_mutations(mutations);
let mut ctx = AnyMap::new();
ctx.insert(3.3);
let _to_rerender = rdom.update_state(vdom, to_update, ctx).unwrap();
// render...
}
})
}
```
## Disposição
Para a maioria das plataformas, o layout dos Elementos permanecerá o mesmo. O módulo layout_attributes fornece uma maneira de aplicar atributos `html` a um estilo de layout estendido.
## Conclusão
Pronto, é isso! Você deve ter quase todo o conhecimento necessário sobre como implementar seu próprio renderizador. Estamos super interessados em ver os aplicativos Dioxus trazidos para renderizadores de desktop personalizados, renderizador para dispositivos móveis, interface do usuário para videogames e até realidade aumentada! Se você estiver interessado em contribuir para qualquer um desses projetos, não tenha medo de entrar em contato ou se juntar à comunidade.
@@ -0,0 +1,31 @@
# Recarregamento a Quente
1. O recarregamento a quente permite tempos de iteração muito mais rápidos dentro de chamadas rsx, interpretando-as e transmitindo as edições.
2. É útil ao alterar o estilo/layout de um programa, mas não ajudará na alteração da lógica de um programa.
3. Atualmente, o cli implementa apenas o recarregamento a quente para o renderizador da web.
# Configurar
Instale o [dioxus-cli](https://github.com/DioxusLabs/cli).
Habilite o recurso hot_reload no dioxus:
```toml
dioxus = { version = "*", features = ["web", "hot_reload"] }
```
# Como Usar
1. run:
```
dioxus serve --hot-reload
```
2. alterar algum código dentro de uma macro rsx
3. abra seu localhost em um navegador
4. salve e observe a mudança de estilo sem recompilar
# Limitações
1. O intérprete só pode usar expressões que existiam na última recompilação completa. Se você introduzir uma nova variável ou expressão na chamada rsx, ela acionará uma recompilação completa para capturar a expressão.
2. Componentes e Iteradores podem conter código de Rust arbitrário e acionarão uma recompilação completa quando alterados.
+1
View File
@@ -0,0 +1 @@
# Guias Avançados
+228
View File
@@ -0,0 +1,228 @@
# RSX in Depth
The RSX macro makes it very easy to assemble complex UIs with a very natural Rust syntax:
```rust
rsx!(
div {
button {
onclick: move |e| todos.write().new_todo(),
"Add todo"
}
ul {
class: "todo-list",
todos.iter().map(|(key, todo)| rsx!(
li {
class: "beautiful-todo"
key: "f"
h3 { "{todo.title}" }
p { "{todo.contents}"}
}
))
}
}
)
```
In this section, we'll cover the `rsx!` macro in depth. If you prefer to learn through examples, the `code reference` guide has plenty of examples on how to use `rsx!` effectively.
### Element structure
Attributes must come before child elements
```rust
div {
hidden: "false",
"some text"
child {}
Component {} // uppercase
component() // lowercase is treated like a function call
(0..10).map(|f| rsx!{ "hi {f}" }) // arbitrary rust expressions
}
```
Each element takes a comma-separated list of expressions to build the node. Roughly, here's how they work:
- `name: value` sets a property on this element.
- `"text"` adds a new text element
- `tag {}` adds a new child element
- `CustomTag {}` adds a new child component
- `{expr}` pastes the `expr` tokens literally. They must be `IntoIterator<T> where T: IntoVnode` to work properly
Commas are entirely optional, but might be useful to delineate between elements and attributes.
The `render` function provides an **extremely efficient** allocator for VNodes and text, so try not to use the `format!` macro in your components. Rust's default `ToString` methods pass through the global allocator, but all text in components is allocated inside a manually-managed Bump arena. To push you in the right direction, all text-based attributes take `std::fmt::Arguments` directly, so you'll want to reach for `format_args!` when the built-in `f-string` interpolation just doesn't cut it.
### Ignoring `cx.render` with `rsx!(cx, ...)`
Sometimes, writing `cx.render` is a hassle. The `rsx! macro will accept any token followed by a comma as the target to call "render" on:
```rust
cx.render(rsx!( div {} ))
// becomes
rsx!(cx, div {})
```
### Conditional Rendering
Sometimes, you might not want to render an element given a condition. The rsx! macro will accept any tokens directly contained with curly braces, provided they resolve to a type that implements `IntoIterator<VNode>`. This lets us write any Rust expression that resolves to a VNode:
```rust
rsx!({
if enabled {
rsx!(cx, div {"enabled"})
} else {
rsx!(cx, li {"disabled"})
}
})
```
A convenient way of hiding/showing an element is returning an `Option<VNode>`. When combined with `and_then`, we can succinctly control the display state given some boolean:
```rust
rsx!({
a.and_then(rsx!(div {"enabled"}))
})
```
It's important to note that the expression `rsx!()` is typically lazy - this expression must be _rendered_ to produce a VNode. When using match statements, we must render every arm as to avoid the `no two closures are identical` rule that Rust imposes:
```rust
// this will not compile!
match case {
true => rsx!(div {}),
false => rsx!(div {})
}
// the nodes must be rendered first
match case {
true => rsx!(cx, div {}),
false => rsx!(cx, div {})
}
```
### Lists
Again, because anything that implements `IntoIterator<VNode>` is valid, we can use lists directly in our `rsx!`:
```rust
let items = vec!["a", "b", "c"];
cx.render(rsx!{
ul {
{items.iter().map(|f| rsx!(li { "a" }))}
}
})
```
Sometimes, it makes sense to render VNodes into a list:
```rust
let mut items = vec![];
for _ in 0..5 {
items.push(rsx!(cx, li {} ))
}
rsx!(cx, {items} )
```
#### Lists and Keys
When rendering the VirtualDom to the screen, Dioxus needs to know which elements have been added and which have been removed. These changes are determined through a process called "diffing" - an old set of elements is compared to a new set of elements. If an element is removed, then it won't show up in the new elements, and Dioxus knows to remove it.
However, with lists, Dioxus does not exactly know how to determine which elements have been added or removed if the order changes or if an element is added or removed from the middle of the list.
In these cases, it is vitally important to specify a "key" alongside the element. Keys should be persistent between renders.
```rust
fn render_list(cx: Scope, items: HashMap<String, Todo>) -> DomTree {
rsx!(cx, ul {
{items.iter().map(|key, item| {
li {
key: key,
h2 { "{todo.title}" }
p { "{todo.contents}" }
}
})}
})
}
```
There have been many guides made for keys in React, so we recommend reading up to understand their importance:
- [React guide on keys](https://reactjs.org/docs/lists-and-keys.html)
- [Importance of keys (Medium)](https://kentcdodds.com/blog/understanding-reacts-key-prop)
### Complete Reference
```rust
let text = "example";
cx.render(rsx!{
div {
h1 { "Example" },
{title}
// fstring interpolation
"{text}"
p {
// Attributes
tag: "type",
// Anything that implements display can be an attribute
abc: 123,
enabled: true,
// attributes also supports interpolation
// `class` is not a restricted keyword unlike JS and ClassName
class: "big small wide short {text}",
class: format_args!("attributes take fmt::Arguments. {}", 99),
tag: {"these tokens are placed directly"}
// Children
a { "abcder" },
// Children with attributes
h2 { "hello", class: "abc-123" },
// Child components
CustomComponent { a: 123, b: 456, key: "1" },
// Child components with paths
crate::components::CustomComponent { a: 123, b: 456, key: "1" },
// Iterators
{ (0..3).map(|i| rsx!( h1 {"{:i}"} )) },
// More rsx!, or even html!
{ rsx! { div { } } },
{ html! { <div> </div> } },
// Matching
// Requires rendering the nodes first.
// rsx! is lazy, and the underlying closures cannot have the same type
// Rendering produces the VNode type
{match rand::gen_range::<i32>(1..3) {
1 => rsx!(cx, h1 { "big" })
2 => rsx!(cx, h2 { "medium" })
_ => rsx!(cx, h3 { "small" })
}}
// Optionals
{true.and_then(|f| rsx!( h1 {"Conditional Rendering"} ))}
// Child nodes
{cx.props.children}
// Any expression that is `IntoVNode`
{expr}
}
}
})
```
@@ -0,0 +1,228 @@
# RSX à Fundo
A macro RSX facilita muito a montagem de interfaces de usuário complexas com uma sintaxe Rust muito natural:
```rust
rsx!(
div {
button {
onclick: move |e| todos.write().new_todo(),
"Add todo"
}
ul {
class: "todo-list",
todos.iter().map(|(key, todo)| rsx!(
li {
class: "beautiful-todo"
key: "f"
h3 { "{todo.title}" }
p { "{todo.contents}"}
}
))
}
}
)
```
Nesta seção, abordaremos a macro `rsx!` em profundidade. Se você preferir aprender através de exemplos, o guia `referência de código` tem muitos exemplos sobre como usar `rsx!` efetivamente.
### Estrutura do elemento
Os atributos devem vir antes dos elementos filhos
```rust
div {
hidden: "false",
"some text"
child {}
Component {} // uppercase
component() // lowercase is treated like a function call
(0..10).map(|f| rsx!{ "hi {f}" }) // arbitrary rust expressions
}
```
Cada elemento usa uma lista de expressões separadas por vírgulas para construir o nó. A grosso modo, veja como eles funcionam:
- `name: value` define uma propriedade neste elemento.
- `text` adiciona um novo elemento de texto
- `tag {}` adiciona um novo elemento filho
- `CustomTag {}` adiciona um novo componente filho
- `{expr}` cola os tokens `expr` literalmente. Eles devem ser `IntoIterator<T> where T: IntoVnode` para funcionar corretamente
As vírgulas são totalmente opcionais, mas podem ser úteis para delinear entre elementos e atributos.
A função `render` fornece um alocador **extremamente eficiente** para `VNodes` e `text`, então tente não usar a macro `format!` em seus componentes. Os métodos `ToString` padrão do Rust passam pelo alocador global, mas todo o texto nos componentes é alocado dentro de uma ""arena Bump"" gerenciada manualmente. Para levá-lo na direção certa, todos os atributos baseados em texto recebem `std::fmt::Arguments` diretamente, então você vai querer usar `format_args!` quando a interpolação interna `f-string` simplesmente não funcionar.
### Ignorando `cx.render` com `rsx!(cx, ...)`
Às vezes, escrever `cx.render` é um aborrecimento. O `rsx!` macro aceitará qualquer token seguido por uma vírgula como destino para chamar "render" em:
```rust
cx.render(rsx!( div {} ))
// becomes
rsx!(cx, div {})
```
### Renderização Condicional
Às vezes, você pode não querer renderizar um elemento dada uma condição. O `rsx!` macro aceitará quaisquer tokens contidos diretamente com chaves, desde que resolvam para um tipo que implemente `IntoIterator<VNode>`. Isso nos permite escrever qualquer expressão Rust que resolva para um `VNode`:
```rust
rsx!({
if enabled {
rsx!(cx, div {"enabled"})
} else {
rsx!(cx, li {"disabled"})
}
})
```
Uma maneira conveniente de ocultar/mostrar um elemento é retornar um `Option<VNode>`. Quando combinado com `and_then`, podemos controlar sucintamente o estado de exibição dado alguns booleanos:
```rust
rsx!({
a.and_then(rsx!(div {"enabled"}))
})
```
É importante notar que a expressão `rsx!()` é tipicamente tardia - esta expressão deve ser _renderizada_ para produzir um `VNode`. Ao usar declarações de `match`, devemos renderizar todos os braços para evitar a regra 'não há dois fechamentos idênticos' que o Rust impõe:
```rust
// this will not compile!
match case {
true => rsx!(div {}),
false => rsx!(div {})
}
// the nodes must be rendered first
match case {
true => rsx!(cx, div {}),
false => rsx!(cx, div {})
}
```
### Listas
Novamente, porque qualquer coisa que implemente `IntoIterator<VNode>` é válida, podemos usar listas diretamente em nosso `rsx!`:
```rust
let items = vec!["a", "b", "c"];
cx.render(rsx!{
ul {
{items.iter().map(|f| rsx!(li { "a" }))}
}
})
```
Às vezes, faz sentido renderizar `VNodes` em uma lista:
```rust
let mut items = vec![];
for _ in 0..5 {
items.push(rsx!(cx, li {} ))
}
rsx!(cx, {items} )
```
#### Listas e chaves
Ao renderizar o `VirtualDom` na tela, o Dioxus precisa saber quais elementos foram adicionados e quais foram removidos. Essas mudanças são determinadas através de um processo chamado "diffing" - um antigo conjunto de elementos é comparado a um novo conjunto de elementos. Se um elemento for removido, ele não aparecerá nos novos elementos, e Dioxus sabe removê-lo.
No entanto, com listas, Dioxus não sabe exatamente como determinar quais elementos foram adicionados ou removidos se a ordem mudar ou se um elemento for adicionado ou removido do meio da lista.
Nesses casos, é de vital importância especificar uma "chave" ao lado do elemento. As chaves devem ser persistentes entre as renderizações.
```rust
fn render_list(cx: Scope, items: HashMap<String, Todo>) -> DomTree {
rsx!(cx, ul {
{items.iter().map(|key, item| {
li {
key: key,
h2 { "{todo.title}" }
p { "{todo.contents}" }
}
})}
})
}
```
Existem muitos guias feitos para chaves no React, então recomendamos a leitura para entender sua importância:
- [React guide on keys](https://reactjs.org/docs/lists-and-keys.html)
- [Importância das chaves (Média)](https://kentcdodds.com/blog/understanding-reacts-key-prop)
### Referência Completa
```rust
let text = "example";
cx.render(rsx!{
div {
h1 { "Example" },
{title}
// fstring interpolation
"{text}"
p {
// Attributes
tag: "type",
// Anything that implements display can be an attribute
abc: 123,
enabled: true,
// attributes also supports interpolation
// `class` is not a restricted keyword unlike JS and ClassName
class: "big small wide short {text}",
class: format_args!("attributes take fmt::Arguments. {}", 99),
tag: {"these tokens are placed directly"}
// Children
a { "abcder" },
// Children with attributes
h2 { "hello", class: "abc-123" },
// Child components
CustomComponent { a: 123, b: 456, key: "1" },
// Child components with paths
crate::components::CustomComponent { a: 123, b: 456, key: "1" },
// Iterators
{ (0..3).map(|i| rsx!( h1 {"{:i}"} )) },
// More rsx!, or even html!
{ rsx! { div { } } },
{ html! { <div> </div> } },
// Matching
// Requires rendering the nodes first.
// rsx! is lazy, and the underlying closures cannot have the same type
// Rendering produces the VNode type
{match rand::gen_range::<i32>(1..3) {
1 => rsx!(cx, h1 { "big" })
2 => rsx!(cx, h2 { "medium" })
_ => rsx!(cx, h3 { "small" })
}}
// Optionals
{true.and_then(|f| rsx!( h1 {"Conditional Rendering"} ))}
// Child nodes
{cx.props.children}
// Any expression that is `IntoVNode`
{expr}
}
}
})
```
+45
View File
@@ -0,0 +1,45 @@
# Getting Started: Desktop
One of Dioxus' killer features is the ability to quickly build a native desktop app that looks and feels the same across platforms. Apps built with Dioxus are typically <5mb in size and use existing system resources, so they won't hog extreme amounts of RAM or memory.
Dioxus Desktop is built off Tauri. Right now there aren't any Dioxus abstractions over keyboard shortcuts, menubar, handling, etc, so you'll want to leverage Tauri - mostly [Wry](http://github.com/tauri-apps/wry/) and [Tao](http://github.com/tauri-apps/tao)) directly. The next major release of Dioxus-Desktop will include components and hooks for notifications, global shortcuts, menubar, etc.
## Getting Set up
Getting Set up with Dioxus-Desktop is quite easy. Make sure you have Rust and Cargo installed, and then create a new project:
```shell
$ cargo new --bin demo
$ cd demo
```
Add Dioxus with the `desktop` feature:
```shell
$ cargo add dioxus --features desktop
```
Edit your `main.rs`:
```rust
// main.rs
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
}
fn app(cx: Scope) -> Element {
cx.render(rsx!{
div {
"hello world!"
}
})
}
```
To configure the webview, menubar, and other important desktop-specific features, checkout out some of the launch configuration in the [API reference](https://docs.rs/dioxus-desktop/).
## Future Steps
Make sure to read the [Dioxus Guide](https://dioxuslabs.com/guide) if you already haven't!
+11
View File
@@ -0,0 +1,11 @@
# Platforms
Dioxus supports many different platforms. Below are a list of guides that walk you through setting up Dioxus for a specific platform.
### Setup Guides
- [Web](web.md)
- [Server Side Rendering](ssr.md)
- [Desktop](desktop.md)
- [Mobile](mobile.md)
- [TUI](tui.md)