Expand description
§Consecuit
An experimental functional web UI framework that uses the Rust type system for hooks and more.
This crate is a library for building web UI with functional components and hooks.
See the README for an overview.
Also take a look at our TodoMVC and its source code.
§Using Consecuit
Below, we show you how to
- Write and use hooks.
- Write and use components.
- Write and use container components.
The the counters example is also good for getting started.
§Hooks
A Consecuit hook is a function that can call other Consecuit hooks.
So you can build your own hook by composing the basic hooks like use_state
, use_ref
, and use_effect
.
A Consecuit hook must be a function that takes 2 arguments:
Consecuit’s HookBuilder
, and the args, which can be any type.
The return type should not be named out concretely, but rather written as impl Trait
of HookReturn
, with the actual value as the generic parameter.
The signature for a use_i32_state
hook might look something like this
use consecuit::prelude::*;
fn use_i32_state(cc: HookBuilder, initial_value: i32) -> impl HookReturn<(i32, Updater<i32>)>
In the function body, you can write code just like a normal function.
To use other hooks, call cc.hook(<hook function>, <hook args>)
.
This will consume cc
and return a new one, along with the return value of the hook, in a tuple like this (cc. <hook return value>)
.
You then can do whatever you want with the <hook return value>
, and you can use the use the returned cc
to call more hooks.
let (cc, some_hook_result) = cc.hook(some_hook_function, some_hook_args);
println!("{:?}", some_hook_result + 1);
let (cc, another_hook_result) = cc.hook(another_hook_function, another_hook_args);
When you are done and want to return from your hook, return (cc, <your hook return value>)
.
(cc, some_value)
Our use_i32_state
might look like this in full:
use consecuit::prelude::*;
fn use_i32_state(cc: HookBuilder, initial_value: i32) -> impl HookReturn<(i32, Updater<i32>)> {
// Use the `use_state` hook.
let (cc, (number, updater)) = cc.hook(use_state, initial_value);
// Print the value.
prinln!("The state is {}", number.to_string());
// Return
(cc, (number, updater))
}
Take a look at the counters example,
specifically the function counter_hook_extracted
, to see how we extract logic into a new hook.
§Components
A Consecuit component is a function that can call Consecuit hooks, and render other Consecuit components. You can use the HTML components provided by the consecuit_html crate as building blocks for your components’ UI.
A Consecuit component must be a function that takes 2 arguments:
Consecuit’s ComponentBuilder
, and the props, which can be any type that is PartialEq
and Clone
, and 'static
(i.e. not a borrow).
(a component can only have 1 props).
The return type should not be named out concretely, but rather written as impl Trait
of ComponentReturn
.
Here is an example:
use consecuit::prelude::*;
fn my_component(cc: ComponentBuilder, props: MyComponentProps) -> impl ComponentReturn
In the function body, you can write normal code, and call hooks the same way as for hook functions documented above.
You can also use the cc_tree
macro to render other components. Like this:
use consecuit_html::prelude::*; // <- consecuit_html provides html components like div and span
cc_tree!(
<div>
<div {html_props().class_name("some-class-name").onclick(onclick_callback)}>
<span>"I'm a string literal"</span>
<span {html_props().class_name("span-text")}>{format!("anything that is AsRef<str> works")}</span>
{props.some_text}
<my_component { MyComponentProps {text: "hello"} } />
</div>
<div {html_props().class_name("nothing-here")} />
</div>
)
As you might have figured out from the code above already:
- Use the name of the component function is the name of the tag.
- Put the props in curly braces beside the tag name.
If there are none, the macro will attempt to use the
Default::default
value (and error if the props doesn’t implement Default). - Use string literal or any
AsRef<str>
type in braces to create text node.
Here is an example of a component function:
use consecuit::prelude::*;
use consecuit_html::prelude::*;
fn show_plus_calculation(cc: ComponentBuilder, (lhs, rhs): (i32, i32)) -> impl ComponentReturn {
let result = lhs + rhs;
// These 2 lines are just to show how to use hooks
let (cc, _some_example_1) = cc.hook(use_example_hook, 1234);
let (cc, _some_example_2) = cc.hook(use_another_hook, 5678);
// All there `h5`, `span`, `b` are from the `consecuit_html` crate.
cc_tree!(
<my_website_header />
<h5>"Calculation Result:"</h5>
<span>{lhs.to_string()}</span>
<span {html_props().class_name("plus-sign")}>" + "</span>
<span>{rhs.to_string()}</span>
<span {html_props().class_name("equal-sign")}>" = "</span>
<span><b>{result.to_string()}</b></span>
<my_website_footer />
)
}
§Container Components
Container components are components with ‘hole’, allowing you to give it children.
Most components in the consecuit_html
crate are containers.
Container components return impl ContainerReturn
rather than impl ComponentReturn
For example, you can give div and span childrens:
cc_tree!(
<div>
"This is a child I put in the div"
"This is another child I put in the div"
<span>"This is a child I put in the span in the div"</span>
</div>
)
To create your own container component, add the HOLE
attribute to the component you wish to hole.
This will “forward” the hole of that component.
For example:
fn my_container(cc: ComponentBuilder, _: ()) -> impl ContainerReturn {
cc_tree!(
<div>
"The hole of the div below is forwarded to become the hole of my_container!"
<div HOLE />
</div>
)
}
A container component must have exactly one hole.
Re-exports§
pub use construction::mount;
pub use consecuit_macros;
Modules§
- construction
- The important internal mechanisms are in here.
- executor
- Render queue and batching.
- hooks
- Essential hooks you can build other hooks with.
- locking
- Locking mechanism. Don’t mind this.
- prelude
- Just import me.