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:
Inputis the regularMsgtype from theModeltrait in 0.4.Outputis 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.CmdOutputis the output of commands. Commands are futures that are executed in the background. They fully replace async workers. The result of this future is theCmdOutputmessage 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 
Someis 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 theinitfunction to inject the code from theviewmacro. 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_cssnow takes&stras 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.