Migration from v0.4 to v0.5
Version 0.5 brings many exciting changes but also a few major breaking changes. In this chapter, all changes should be covered to help you migrating your existing code quickly.
Components
Component
unifies several traits that existed before.
It entirely replaces AppUpdate
, ComponentUpdate
, AsyncComponentUpdate
, MessageHandler
, MicroModel
, MicroWidgets
, Components
and Widgets
.
Components are now more similar to MicroComponent
which means they are much more flexible and don't need a typed connection to their parent component.
This makes using the same component with different parent components much easier.
Instead of accessing the parent model, you define Init
as a type that includes all information to initialize the component.
The life cycle has changed a bit, too.
- Initialization of the root widget. The reason behind this is to allow parent components to access the root widget before the rest of the component is initialized.
- Initialize the component itself and the widgets. This happens in one method now, which makes it easier especially for more difficult initializations.
- Regarding updates, there hasn't been a lot of changes. However you can now optionally update view and model at once using
update_with_view
. - The shutdown method is called when the component is destroyed. Components don't have to live for the entire application lifespan anymore.
Senders and messages
Components have three kinds of messages now:
Input
is the regularMsg
type from theModel
trait in 0.4.Output
is the message type, that can be used to forward information to other components automatically (or()
if you don't care about forwarding). You will find more information about initializing components in the next section.CmdOutput
is the output of commands. Commands are futures that are executed in the background. They fully replace async workers. The result of this future is theCmdOutput
message handled inupdate_cmd
, similar to the regular update function.
The send!
macro is obsolete. Please use sender.input(msg)
instead.
Initializing components
Components are initialized in the init method of their parent.
You simply call MyComponentType::builder()
to get a ComponentBuilder
.
Then you launch the component by calling builder.launch(init_params)
to receive a Connector
.
From the connector you can decide to automatically forward messages to another component or just detach the connector to get a Controller
.
The controller is the type you now store in the model of the parent component instead of creating a separate components struct.
There's no Components
trait necessary.
For types that implement Component
that don't have any widgets (such as implementers of the Worker
trait), you can call detach_worker
from a ComponentBuilder
.
This spawns the internal runtime on a separate thread and gives you a WorkerController
.
Helper traits
SimpleComponent
SimpleComponent
is a simpler variant of Component
that helps with the implementation of Component
.
Particularly, it doesn't support commands.
Worker
Worker
is an even simpler variant of SimpleComponent
that helps with the implementation of Component
.
Particularly, it doesn't support widgets and allows running the components update loop on a different thread by using detach_worker
.
This is the replacement for the previously separated RelmWorker
type.
Factories
Factories now work very similar to components.
In fact, the new FactoryComponent
trait that replaces FactoryPrototype
is almost identical to the Component
trait.
Messages can now be optionally passed by using the forward_to_parent
method.
FactoryVec
was entirely removed in favor of FactoryVecDeque
.
Edits to factories are now similar to Mutex
and require a guard.
When the guard is dropped, all changes are rendered automatically, so no render method is required anymore.
The view
macro
- In general, a lot of internal macros were moved to be just attributes like
watch!
andtrack!
now written as#[watch]
and#[track(optional_condition)]
. - Multiple arguments now don't need
args!()
but just()
whereas tuples need two parenthesis(())
. - Wrapping widgets into
Some
is now also an attribute#[wrap(Some)]
. - Additional arguments are now passed with square brackets
[]
instead of parenthesis()
. - Cloning variables for closures is always done with square brackets
[]
instead of parenthesis()
.
Old | New |
---|---|
|
|
The widget
macro
- The macro in now called
#[component]
. - You need to use
let widgets = view_output!();
in theinit
function to inject the code from theview
macro. pre_init
-> Code beforeview_output!()
.post_init
-> Code afterview_output!()
.
RelmApp
Now you need to specify an application id and a generic parameter is required when calling run()
.
Miscellaneous
WidgetPlus::inline_css
now takes&str
as parameter instead of&[u8]
.
Summary
v0.4 | v0.5 |
---|---|
Model | Component |
AppUpdate | Component |
ComponentUpdate | Component |
AsyncComponentUpdate | Component |
MicroComponent | Component |
MicroWidgets | Component |
MessageHandler | Component |
FactoryPrototype | FactoryComponent |
Model::Msg | Component::Input |
Model::Widgets | Component::Widgets |
Model::Components | removed |
Components | Store a Controller for each component in your model |
parent_sender | Forward output messages from one component to another by using Connector |
In case there's something missing, please let me know. You can simply open an issue on GitHub or write a message in the Matrix room.