Write a component
With the #[component] macro,
writing a component in frender is
as simple as writing a rust fn.
The macro will turn the fn item to a struct,
and implement
UseRenderStatic
and
ComponentStatic
for it.
The fn body will be the body of UseRenderStatic::use_render method.
The return type of the fn will be UseRenderStatic::RenderOutput.
The optional first arg of the fn will be the props type of this component,
which is UseRenderStatic::RenderArg and [ComponentStatic::Props].
If there is no args in the fn, the props type will be
react::NoProps.
The return type can be omitted.
If omitted, the default return type is
react::Element.
Component with no props
#![allow(unused)] fn main() { use frender::prelude::*; #[component] fn MyComponent() { // ^ // the return type defaults to react::Element rsx!( <div /> ) } fn check_something() -> bool { true } // Or you can specify the return type explicitly #[component] fn MyAnotherComponent() -> Option<react::Element> { if check_something() { Some(rsx!( <MyComponent /> )) } else { None } } }
Component with props
First, define props with def_props macro.
#![allow(unused)] fn main() { use frender::prelude::*; def_props! { pub struct MyProps { // Required prop name: String, // Optional prop which defaults to `Default::default()` // The following property `age` is optional, and defaults to `None` age?: Option<u8>, // The following property `tags` is optional, and defaults to `Vec::default()` tags?: Vec<String>, // If the prop type is not specified, // then frender will infer the type by prop name. // For example, `class_name` default has type `Option<String>` // The following property `class_name` is optional, has type Option<String> class_name?, // The following property `id` is required, has type Option<String> id, // Prop can also have type generics. // For example, the following is // the default definition for prop `children`, // which means it accepts any `Option<TNode>` where TNode implements react::Node, // and then map the value into `Option<react::Children>` and store it into MyProps. children<TNode: react::Node>(value: Option<TNode>) -> Option<react::Children> { value.and_then(react::Node::into_children) }, } } }
Then write the component with the above props:
#![allow(unused)] fn main() { use frender::prelude::*; #[component] pub fn MyComponent(props: &MyProps) { rsx!( <div>{&props.children}</div> ) } }
Due to the generics, in some very rare cases, you may meet errors like
type annotations needed cannot infer type for type parameter.
You can solve it by specifying the type
with the turbofish syntax ::<>.
For example:
#![allow(unused)] fn main() { rsx! ( // ERROR: type annotations needed <a children={None} /> ) rsx! ( // it works! <a children={None::<()>} /> ) }