redraw
Types
Default Node in redraw. Use component
-family functions to create components.
Forwarded ref can be constructed using forward_ref
-family functions, while
external components can be used with to_component
-family functions.
pub type Component
Pass data without props drilling.
pub type Context(a)
A Ref is a mutable data stored in React, persisted across renders. They allow to keep track of a DOM node, a component data, or to store a mutable variable in the component, outside of every component lifecycle.
pub type Ref(a)
Functions
pub fn act(act_fn: fn() -> Promise(Nil)) -> Promise(Nil)
Test helper to apply pending React updates before making assertions.
pub fn component(
name name: String,
render render: fn(a, List(Component)) -> Component,
) -> fn(a, List(Component)) -> Component
Create a Redraw component, with a name
, and a render
function. render
will accept props, and a list of children.
pub fn component_(
name name: String,
render render: fn(a) -> Component,
) -> fn(a) -> Component
Create a Redraw component, with a name
, and a render
function. This
component does not accept children.
pub fn component__(
name name: String,
render render: fn() -> Component,
) -> fn() -> Component
Create a Redraw component, with a name
and a render
function. This
component does not accept children nor props.
pub fn context(
name: String,
default_value: fn() -> a,
) -> Context(a)
context
emulates classic Context usage in React. Instead of calling
create_context_
and get_context
, it’s possible to simply call context
,
which will get or create the context directly, and allows to write code as
if Context is globally available. context
also tries to preserve
type-checking at most. context.default_value
is lazily evaluated, meaning
no additional computations will ever be run.
import redraw
const context_name = "MyContextName"
pub type MyContext {
MyContext(count: Int, set_count: fn (Int) -> Nil)
}
fn default_value() {
let count = 0
les set_count = fn (_) { Nil }
MyContext(count:)
}
pub fn provider() {
use _, children <- redraw.component()
let context = redraw.context(context_name, default_value)
let #(count, set_count) = redraw.use_state(0)
redraw.provider(context, MyContext(count:, set_count:), children)
}
pub fn use_my_context() {
let context = redraw.context(context_name, default_value)
redraw.use_context(context)
}
context
should never fail, but it can be wrong if you use an already used
name.
pub fn create_context(
default_value default_value: Option(a),
) -> Context(a)
Deprecated: Use redraw/create_context_ instead. redraw/create_context will be removed in 2.0.0. Unusable right now, due to how React handles Context.
Let you create a context that components can provide or read.
pub fn create_context_(
name: String,
default_value: a,
) -> Result(Context(a), Error)
Create a context
that components can provide or read.
Each context is referenced by its name, a little bit like actors in OTP
(if you’re familiar with Erlang). Because Gleam cannot execute code outside of
main
function, creating a context should do some side-effect at startup.
In traditional React code, Context usage is usually written like this.
import * as react from 'react'
// Create your Context in a side-effectful way.
const MyContext = react.createContext(defaultValue)
// Create your own provider, wrapping your context.
export function MyProvider(props) {
return <MyContext.Provider>{props.children}</MyContext.Provider>
}
// Create your own hook, to simplify usage of your context.
export function useMyContext() {
return react.useContext(MyContext)
}
To simplify and mimic that usage, Redraw wraps Context creation with some caching, to emulate a similar behaviour.
import redraw
const context_name = "MyContextName"
pub fn my_provider(children) {
let assert Ok(context) = redraw.create_context_(context_name, default_value)
redraw.provider(context, value, children)
}
pub fn use_my_context() {
let assert Ok(context) = redraw.get_context(context_name)
redraw.use_context(context)
}
Be careful, create_context_
fails if the Context is already defined.
Choose a full qualified name, hard to overlap with inattention. If
you want to get a Context in an idempotent way, take a look at context()
.
pub fn forward_ref(
name name: String,
render render: fn(a, Ref(b), List(Component)) -> Component,
) -> fn(a, Ref(b), List(Component)) -> Component
Create a Redraw component with children with forwarded ref. Take a look at
pub fn forward_ref_(
name name: String,
render render: fn(a, Ref(b)) -> Component,
) -> fn(a, Ref(b)) -> Component
Create a Redraw component without children with forwarded ref. Take a look at
pub fn fragment(children: List(Component)) -> Component
Fragment allow to group children, without creating a node in the DOM.
pub fn get_context(name: String) -> Result(Context(a), Error)
Get a context. Because of FFI, get_context
breaks the type-checker. It
should be considered as unsafe code. As a library author, never exposes
your context and expect users will call get_context
themselves, but rather
exposes a use_my_context()
function, handling the type-checking for the
user.
import redraw
pub type MyContext {
MyContext(value: Int)
}
/// `use_context` returns `Context(a)`, should it can be safely returned as
/// `Context(MyContext)`.
pub fn use_my_context() -> redraw.Context(MyContext) {
let context = case redraw.get_context("MyContextName") {
// Context has been found in the context cache, use it as desired.
Ok(context) -> context
// Context has not been found. It means the user did not initialised it.
Error(_) -> panic as "Unitialised context."
}
redraw.use_context(context)
}
pub fn keyed(
element: fn(List(Component)) -> Component,
content: List(#(String, Component)),
) -> Component
Redraw does not support passing key element to components in an easy way like React does. To simplify this, it uses the same API than Lustre to put keys on children.
fn my_component(props, children) {
redraw.keyed(my_other_component(props, _), {
use item <- list.map(children)
#("my-key", item)
})
}
pub fn memo(
component: fn(a, List(Component)) -> Component,
) -> fn(a, List(Component)) -> Component
Memoizes a Redraw component with children.
pub fn memo_(component: fn(a) -> Component) -> fn(a) -> Component
Memoizes a Redraw component without children.
pub fn profiler(children: List(Component)) -> Component
Profile allows to measure code performance for a component tree.
pub fn provider(
context context: Context(a),
value value: a,
children children: List(Component),
) -> Component
Wrap your components into a context provider to specify the value of this context for all components inside.
pub fn set_current(of ref: Ref(a), with value: a) -> Nil
Set the current value of a ref, overriding its existing content.
pub fn start_transition(scope scope: fn() -> Nil) -> Nil
Let you update the state without blocking the UI.
pub fn strict_mode(children: List(Component)) -> Component
Strict Mode should be enabled during development.
pub fn suspense(
props: Suspense,
children: List(Component),
) -> Component
Suspense allow to display a fallback content while waiting for children to finish loading.
pub fn to_component(
name name: String,
component render: fn(a) -> Component,
) -> fn(b, List(Component)) -> Component
Convert a React component to a React-redraw component with children. Give it a name, and send directly the FFI. Don’t worry about the snake_case over camelCase, redraw take care of it for you.
import redraw
@external(javascript, "my_library", "MyComponent")
fn do_my_component(props: props) -> redraw.Component
pub type MyComponentProps {
MyComponentProps(
first_prop: Bool,
second_prop: String,
)
}
pub fn my_component() -> fn(MyComponentProps) -> redraw.Component {
redraw.to_component("MyComponent", do_my_component)
}
pub fn to_component_(
name name: String,
component render: fn(a) -> Component,
) -> fn(b) -> Component
Convert a React Component to a redraw Component without children. Give it a name, and send directly the FFI. Don’t worry about the snake_case over camelCase, redraw take care of it for you.
import redraw
@external(javascript, "my_library", "MyComponent")
fn do_my_component(props: props) -> redraw.Component
pub type MyComponentProps {
MyComponentProps(
first_prop: Bool,
second_prop: String,
)
}
pub fn my_component() -> fn(MyComponentProps) -> redraw.Component {
redraw.to_component_("MyComponent", do_my_component)
}
pub fn use_callback(fun: a, dependencies: b) -> a
Let you cache a function definition between re-renders.
dependencies
should be a tuple.
pub fn use_context(context: Context(a)) -> a
Let you read and subscribe to context from your component.
pub fn use_debug_value(value: a) -> Nil
Let you add a label to a custom Hook in React DevTools.
pub fn use_debug_value_(
value: a,
formatter: fn(a) -> String,
) -> Nil
Let you add a label to a custom Hook in React DevTools, but allow to format it before.
pub fn use_deferred_value(value: a) -> a
Let you defer updating a part of the UI.
pub fn use_effect(value: fn() -> Nil, dependencies: a) -> Nil
Let you synchronize a component with an external system.
pub fn use_effect_(
value: fn() -> fn() -> Nil,
dependencies: a,
) -> Nil
Let you synchronize a component with an external system. Allow to return a cleanup function.
pub fn use_id() -> String
Generate unique IDs that can be passed to accessibility attributes.
pub fn use_imperative_handle(
ref: Ref(Option(a)),
handler: fn() -> a,
dependencies: b,
) -> Nil
Let you customize the handle exposed as a ref.
Use use_imperative_handle
when you want to customize the data stored in
a ref. It’s mostly used in conjuction with forward_ref
.
pub fn use_imperative_handle_(
ref: Ref(a),
handler: fn() -> a,
dependencies: b,
) -> Nil
Let you customize the handle exposed as a ref.
Use use_imperative_handle
by default, unless you really know what you’re
doing.
pub fn use_layout_effect(
value: fn() -> Nil,
dependencies: a,
) -> Nil
Version of useEffect that fires before the browser repaints the screen.
pub fn use_lazy_state(
initial_value: fn() -> a,
) -> #(a, fn(a) -> Nil)
Let you add a state variable to your component. Allow to create the initial value in a lazy way.
pub fn use_lazy_state_(
initial_value: fn() -> a,
) -> #(a, fn(fn(a) -> a) -> Nil)
Let you add a state variable to your component.
Allow to create the initial value in a lazy way.
Give an updater
function instead of a state setter.
pub fn use_memo(calculate_value: fn() -> a, dependencies: b) -> a
Let you cache the result of a calculation between re-renders.
pub fn use_reducer(
reducer: fn(a, b) -> a,
initial_state: a,
) -> #(a, fn(b) -> Nil)
Let you add a reducer to your component.
pub fn use_reducer_(
reducer: fn(a, b) -> a,
initializer: c,
init: fn(c) -> a,
) -> #(a, fn(b) -> Nil)
Let you add a reducer to your component. Allow to initialize the store in a custom way.
pub fn use_ref() -> Ref(Option(a))
Let you reference a value that’s not needed for rendering.
Most used ref you’ll want to create. They’re automatically created to None
,
and can be passed to attribute.ref
or use_imperative_handle
.
You probably don’t want the ref value to be anything than Option(a)
, unless
you have really strong reasons.
pub fn use_ref_(initial_value: a) -> Ref(a)
Let you reference a value that’s not needed for rendering.
Use use_ref
if you’re trying to acquire a reference to a child or to a
component. Use use_ref_
when you want to keep track of a data, like if
you’re doing some side-effects, in conjuction with get_current
and
set_current
.
pub fn use_state(initial_value: a) -> #(a, fn(a) -> Nil)
Let you add a state variable to your component.
pub fn use_state_(
initial_value: a,
) -> #(a, fn(fn(a) -> a) -> Nil)
Let you add a state variable to your component.
Give an updater
function instead of a state setter.
pub fn use_transition() -> #(Bool, fn() -> Nil)
Let you update the state without blocking the UI.