Skip to main content

Lenses

Lenses are a core concept in Refract, providing a unified interface for managing state, props, effects, and more within your components. They enable you to interact with all aspects of a component's data and lifecycle in a consistent and predictable way.

What is a Lens?

A lens is an object passed to every Refract component. It gives you access to:

  • Props: The properties passed to your component.
  • State: Local reactive state via lens.useRefraction.
  • Effects: Side effects via lens.useEffect.
  • Computed Values: Derived state via lens.useComputed.
  • Custom Hooks: Encapsulated logic via lens.useOptic.
  • Streams: Reactive streams for advanced scenarios.

Basic Usage

import { createComponent } from "refract-js";

const Counter = createComponent(({ lens }) => {
const count = lens.useRefraction(0);

lens.useEffect(() => {
document.title = `Count: ${count.value}`;
}, [count.value]);

return (
<div>
<h1>Count: {count.value}</h1>
<button onClick={() => count.set(count.value + 1)}>Increment</button>
</div>
);
});

Accessing Props

Props are available directly on the lens:

const Greeting = createComponent(({ lens }) => {
return <h2>Hello, {lens.props.name}!</h2>;
});

Creating Local State

Use lens.useRefraction to create local reactive state:

const Toggle = createComponent(({ lens }) => {
const isOpen = lens.useRefraction(false);
return (
<button onClick={() => isOpen.set(!isOpen.value)}>
{isOpen.value ? "Open" : "Closed"}
</button>
);
});

Using Effects

Run side effects with lens.useEffect:

const Timer = createComponent(({ lens }) => {
const seconds = lens.useRefraction(0);

lens.useEffect(() => {
const id = setInterval(() => {
seconds.set(seconds.value + 1);
}, 1000);
return () => clearInterval(id);
}, []);

return <div>Seconds: {seconds.value}</div>;
});

Computed Values

Create derived state with lens.useComputed:

const Price = createComponent(({ lens }) => {
const amount = lens.useRefraction(10);
const tax = lens.useRefraction(0.2);
const total = lens.useComputed(() => amount.value * (1 + tax.value));

return <div>Total: ${total.value.toFixed(2)}</div>;
});

Custom Hooks with Optics

Encapsulate reusable logic with lens.useOptic:

function useCounter(lens, initial = 0) {
const count = lens.useRefraction(initial);
const increment = () => count.set(count.value + 1);
const decrement = () => count.set(count.value - 1);
return { count, increment, decrement };
}

const Counter = createComponent(({ lens }) => {
const { count, increment, decrement } = lens.useOptic(useCounter, 5);
return (
<div>
<button onClick={decrement}>-</button>
<span>{count.value}</span>
<button onClick={increment}>+</button>
</div>
);
});

Summary

Lenses provide a single, consistent API for all component needs in Refract. By using the lens, you can manage state, props, effects, and more with clarity and simplicity.