# Component Simi is inspired by Yew. But Simi component is very different compare to Yew. A component in Yew can effectively run as a standalone app because it has its own messages and data state. Simi component is very simple, it does not have neither state nor message. It just looks into some data that is a reference from the app's state and render its view. A component is a struct that implements `Component` trait. Also, in the `render` method, you must use macro `component!` instead of `application!` ```rust struct MessagePanel<'a> { // This is a reference to a value in the main app state message: &'a String } impl Component for MessagePanel<'_> { fn render(&self, context: RenderContext) { // Here will use `component!` (not `application!`) component! { p { "The message is: " self.message } } } } ``` You use a component in a simi app like this: ```rust application! { // A CamelCase identifier will be intepreted as a simi's component MessagePanel { message: &self.message } } ``` ## Pass event hanlders to a component A useful component should allow to assign different event handlers for each of its instance. You can look in `examples/counter-component` for a working example. First, we define a component `Counter` that has 2 event handler. ```rust struct Counter<'a, A: Application> { title: &'static str, value: &'a i32, // To receive element event handlers from the parent. // They are Cell>> to allow the inner handler to be taken out. up: ElementEventHandler, down: ElementEventHandler, } ``` If you put your components inside a sub `mod`, you will have to add `pub` to all of its struct fields. Otherwise, the compiler will complain about private fields. Then, implementation for our component: ```rust impl Component for Counter<'_, A> { fn render(&self, context: RenderContext) { component! { //@debug p { #self.title self.value } // ^ `#` tell the macro to exclude the subsequent value from updating (only init it in the first render). // because we know that the title will never change button (onclick=#self.down) { "Down" } // ^^^^^ the macro assumes that an event handler start with `self.` is a placeholder for // the actual handler that will be passed here later // ^ `#`: the event handler will also be excluded from updating. If a new handler was passed here // on update, it will be ignored. button (onclick=#self.up) { "Up" } } } } ``` And finally, use our component for different data: ```rust application!{ Counter { title: "Month: ", value: &self.month, // This event handler is never change, but the macro `application!` do not understand it, // therefore, if you want to exclude it from updating, prefix it with `#`, then the macro will // pass `None` to the component on updating. Otherwise, a new event handler will be created // and pass to the component everytime `render` execute. up: onclick=#Msg::MonthUp, // ^^^^^^^^ we need these tokens for an element event, because the macro doesn't know // anything about the component, hence, it doesn't known what kind of event to create here // unless we tell it that the event is `onclick` down: onclick=#Msg::MonthDown, } // A second use of component Counter Counter { title: "Year: ", value: &self.year, up: onclick=#Msg::YearUp, down: onclick=#Msg::YearDown, } } ``` ### Known issue #### Mismatched events If you instantiate the `Counter` like this: ```rust application! { Counter { title: "Year: ", value: &self.year, up: onchange=#Msg::YearUp, // ^^^^^^^^ not onclick here down: onclick=#Msg::YearDown, } } ``` The code just being compiled without a warning. *I will take a look at this later, but not sure when!* ## Nested component This allow you pass a component to another component. A working example is at `examples/counter-nested-component`. The first step, defines a a component that receives another components as children: ```rust struct ParentComponent<'a, A: Application> { message: &'static str, child1: Box + 'a>, child2: Box + 'a>, } impl Component for ParentComponent<'_, A> { fn render(&self, context: RenderContext) { component! { //@debug fieldset { legend { "This is a `ParentComponent`" } p { // Without `$` prefix, this will be process as a Text node self.message } // You must prefix a child component with `$` $ self.child1 $ self.child2 } } } } ``` Second, render the `ParentComponent` with two `Counter` components: ```rust application! { ParentComponent { message: "This component renders two child-components:", child1: Counter { title: "Month: ", value: &self.month, up: onclick=#Msg::MonthUp, down: onclick=#Msg::MonthDown, } child2: Counter { title: "Year: ", value: &self.year, up: onclick=#Msg::YearUp, down: onclick=#Msg::YearDown, } } } ```