frender is still in alpha and it's api might change.
For now it is recommended to specify the exact version in Cargo.toml
.
Before updating, please see the full changelog in case there are breaking changes.
There are some example apps in
examples
folder. You can preview them at this site.
Create a new cargo project
sh
cargo new my-frender-app
cd my-frender-app
Add frender
to dependencies in Cargo.toml
.
toml
[dependencies]
frender = "= 1.0.0-alpha.8"
Create index.html
in the project root directory.
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>My frender App</title>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<link data-trunk rel="rust" href="Cargo.toml" />
</head>
<body>
<div id="frender-root"></div>
</body>
</html>
Modify src/main.rs
```rust use frender::prelude::*;
fn Main() { rsx!(
Run with trunk
Install trunk and then execute:
sh
trunk serve
Then you can navigate to http://localhost:8080
to see your frender app.
rsx
syntaxrsx
element```rust use frender::prelude::*;
rsx! (
// Prop without value means `true`, just like React
<MyDialog show />
// Fragment
<>1 2 3</>
// Fragment with key
<# key="key">1 2 3</#>
// you can also use `</_>` to enclose any element
<path::to::Component></_>
// the above is equivalent to:
<path::to::Component></path::to::Component>
) ```
Any component name starting with lower case letter [a-z]
will be interpreted as an intrinsic component.
For example, rsx!( <div id="my-div" /> )
will be resolved to:
```rust use frender::prelude::; use self::intrinsic_components::div::prelude::;
rsx! (
rsx
propIn order to make rsx less verbose, frender provides
IntoPropValue
trait. The value
in
<MyComponent prop={value} />
will be mapped to
IntoPropValue::into_prop_value(value)
.
With this, assuming the prop accepts Option<i32>
,
you can simplify prop={Some(1)}
to prop={1}
,
because T
implements IntoPropValue<Option<T>>
.
If you want to pass the value as is, you can
use :=
to set prop. prop:={value}
```rust use frender::prelude::*;
fn MyComponent() { // ^ // the return type defaults to react::Element rsx!(
) }// Or you can specify the return type explicitly
fn MyAnotherComponent() -> Option
First, define MyProps
```rust 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:
```rust use frender::prelude::*;
pub fn MyComponent(props: &MyProps) { rsx!(
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:
rust
rsx! (
// ERROR: type annotations needed
<a children={None} />
)
rsx! (
// it works!
<a children={None::<()>} />
)
React hooks are also available in frender
.
You checkout the examples for the usage.
frender
components to jsCssProperties
emotion/react
)frender
is open sourced at GitHub.
Pull requests and issues are welcomed.
You can also sponsor me and I would be very grateful :heart: