You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/src/guide/hello_world.md
+37-83Lines changed: 37 additions & 83 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -30,18 +30,14 @@ To turn it into an app, we need to implement the `App` trait from the
30
30
```rust,noplayground
31
31
use crux_core::App;
32
32
33
-
#[derive(Default)]
34
-
pub struct Model;
35
-
36
33
impl App for Hello {}
37
34
```
38
35
39
36
If you're following along, the compiler is now screaming at you that you're
40
-
missing four associated types for the trait: `Event`, `Model`, `ViewModel` and
41
-
`Capabilities`.
37
+
missing five associated types for the trait — `Event`, `Model`, `ViewModel`,
38
+
`Capabilities`, (which will be deprecated soon, and can be set to `()`) and `Effect`.
42
39
43
-
Capabilities is the more complicated of them, and to understand what it does, we
44
-
need to talk about what makes Crux different from most UI frameworks.
40
+
The `Effect` associated type is worth understanding further, but in order to do that we need to talk about what makes Crux different from most UI frameworks.
45
41
46
42
## Side-effects and capabilities
47
43
@@ -60,7 +56,7 @@ but it doesn't need to know or care whether that database is local or remote.
60
56
That decision can even change as the application evolves, and be different on
61
57
each platform. If you want to understand this better before we carry on, you can
62
58
read a lot more about how side-effects work in Crux in the chapter on
63
-
[capabilities](./capabilities.md).
59
+
[Managed Effects](./effects.md).
64
60
65
61
To _ask_ the Shell for side effects, it will need to know what side effects it
66
62
needs to handle, so we will need to declare them (as an enum). _Effects_ are
@@ -72,53 +68,32 @@ for requesting side-effects. We'll look at them in a lot more detail later.
72
68
Let's start with the basics:
73
69
74
70
```rust,noplayground
75
-
use crux_core::render::Render;
76
-
77
-
pub struct Capabilities {
78
-
render: Render<Event>,
71
+
use crux_core::{
72
+
macros::effect,
73
+
render::RenderOperation,
74
+
};
75
+
76
+
#[effect]
77
+
pub enum Effect {
78
+
Render(RenderOperation),
79
79
}
80
80
```
81
81
82
-
As you can see, for now, we will use a single capability, `Render`, which is
83
-
built into Crux and available from the `crux_core` crate. It simply tells the
84
-
shell to update the screen using the latest information.
85
-
86
-
That means the core can produce a single `Effect`. It will soon be more than
87
-
one, so we'll wrap it in an enum to give ourselves space. The `Effect` enum
88
-
corresponds one to one to the `Capabilities` we're using, and rather than typing
89
-
it (and its associated trait implementations) by hand and open ourselves to
90
-
unnecessary mistakes, we can use the `crux_core::macros::Effect` derive macro.
82
+
As you can see, for now, we will use a single capability, `crux_core::render`, which declares an `Operation` named `RenderOperation`, is built into Crux and is available from the `crux_core` crate. It simply tells the shell to update the screen using the latest information.
91
83
92
-
```rust,noplayground
93
-
use crux_core::render::Render;
94
-
use crux_core::macros::Effect;
95
-
96
-
#[derive(Effect)]
97
-
pub struct Capabilities {
98
-
render: Render<Event>,
99
-
}
100
-
```
84
+
That means the core can produce a single `Effect`. It will soon be more than one, so we'll wrap it in an enum to give ourselves space. We'll also annotate our `Effect` enum with the `crux_core::macros::effect` attribute, which produces a _real_`Effect` enum (which is very similar), one for FFI across the boundary to the shell, and various trait implementations and test helpers.
101
85
102
-
Other than the `derive` itself, we also need to link the effect to our app.
103
-
We'll go into the detail of why that is in the [Capabilities](capabilities.md)
104
-
section, but the basic reason is that capabilities need to be able to send the
105
-
app the outcomes of their work.
86
+
We also need to link the effect to our app. We'll go into the detail of why that is in the [Managed Effects](effects.md) section, but the basic reason is that capabilities need to be able to send the outcomes of their work back into the app.
106
87
107
-
You probably also noticed the `Event` type which capabilities are generic over,
108
-
because they need to know the type which defines messages they can send back to
109
-
the app. The same type is also used by the Shell to forward any user
110
-
interactions to the Core, and in order to pass across the FFI boundary, it needs
111
-
to be serializable. The resulting code will end up looking like this:
88
+
You probably also noticed the `Event` type, which defines messages that can be sent back to the app. The same type is also used by the Shell to forward any user interactions to the Core, and in order to pass across the FFI boundary, it needs to be serializable. The resulting code will end up looking like this:
112
89
113
90
```rust,noplayground
114
-
use crux_core::{render::Render, App};
115
-
use crux_core::macros::Effect;
91
+
use crux_core::{App, macros::effect, render::RenderOperation};
Let's make things more interesting and add some behaviour. We'll teach the app
@@ -290,7 +259,7 @@ You can find the full code for this part of the guide [here](https://github.com/
290
259
```
291
260
292
261
We'll add a simple integration with a counter API we've prepared at
293
-
<https://crux-counter.fly.dev>. All it does is count up an down like our local
262
+
<https://crux-counter.fly.dev>. All it does is count up and down like our local
294
263
counter. It supports three requests
295
264
296
265
-`GET /` returns the current count
@@ -374,7 +343,7 @@ fn update(
374
343
&self,
375
344
event: Self::Event,
376
345
model: &mut Self::Model,
377
-
_caps: &Self::Capabilities,
346
+
_caps: &(), // will be deprecated, so prefix with underscore for now
378
347
) -> Command<Effect, Event> {
379
348
match event {
380
349
Event::Get => {
@@ -436,31 +405,18 @@ there's currently a technical limitation stopping us easily serializing
436
405
sent by the Shell across the FFI boundary, which is the reason for the need to
437
406
serialize in the first place — in a way, it is private to the Core.
438
407
439
-
Finally, let's get rid of those TODOs. We'll need to add crux_http in the
440
-
`Capabilities` type, so that the `update` function has access to it.
441
-
442
-
```admonish note
443
-
In the latest versions of `crux_http` (>= `v0.11.0`), this `Capabilities` type
444
-
id being deprecated in favour of the new `Command` API (see the description of
445
-
[Managed Effects](./effects.md) for more details).
446
-
```
408
+
Finally, let's get rid of those TODOs. We'll need to add a variant to the
409
+
`Effect` enum, which holds the data for Http requests and responses.
410
+
In the snippet, below, `HttpRequest` is an implementation (in `crux_http`) of the `Operation` trait, which links the request and response types together.
447
411
448
412
```rust,noplayground
449
-
use crux_http::Http;
450
-
451
-
#[derive(Effect)]
452
-
pub struct Capabilities {
453
-
pub http: Http<Event>,
454
-
pub render: Render<Event>,
413
+
#[effect(typegen)]
414
+
pub enum Effect {
415
+
Render(RenderOperation),
416
+
Http(HttpRequest),
455
417
}
456
418
```
457
419
458
-
This may seem like needless boilerplate, but it allows us to only use the
459
-
capabilities we need and, more importantly, allow capabilities to be built by
460
-
anyone. Later on, we'll also see that Crux apps [compose](composing.md), relying
461
-
on each app's `Capabilities` type to declare its needs, and making sure the
462
-
necessary capabilities exist in the parent app.
463
-
464
420
We can now implement those TODOs, so lets do it. We're using the latest `Command` API
465
421
and so the `update` function will return a `Command` that has been created by
466
422
the `crux_http` and `render` capabilities (rather than using the `caps` parameter
@@ -475,8 +431,9 @@ fn update(
475
431
&self,
476
432
event: Self::Event,
477
433
model: &mut Self::Model,
478
-
_caps: &Self::Capabilities,
479
-
) -> Command<Effect, Event> { match event {
434
+
_caps: &(), // will be deprecated, so prefix with underscore for now
435
+
) -> Command<Effect, Event> {
436
+
match event {
480
437
Event::Get => Http::get(API_URL)
481
438
.expect_json()
482
439
.build()
@@ -526,7 +483,7 @@ fn update(
526
483
527
484
There's a few things of note. The first one is that the `.then_send` API at the end
528
485
of each chain of calls to `crux_http` expects a function that wraps its argument
529
-
(a `Result` of a http response) in a variant of `Event`. Fortunately, enum tuple
486
+
(a `Result` of a HTTP response) in a variant of `Event`. Fortunately, enum tuple
530
487
variants create just such a function, and we can use it. The way to read the
531
488
call is "Send a get request, parse the response as JSON, which should be
532
489
deserialized as a `Count`, and then call me again with `Event::Set` carrying the
@@ -543,12 +500,9 @@ You can find the the complete example, including the tests and shell implementat
543
500
[in the Crux repo](https://github.com/redbadger/crux/blob/master/examples/counter/).
544
501
It's interesting to take a closer look at the unit tests:
0 commit comments