Skip to main content

useRefraction

useRefraction is the heart of state management in Refract. It creates reactive state that automatically updates your UI when the data changes - no manual subscriptions or complex state management needed.

Think of it as a supercharged version of React's useState, but with built-in reactivity that works seamlessly across your entire application.

Why useRefraction?​

Traditional state management often requires you to manually connect components to state changes, manage subscriptions, and handle complex update patterns. Refract's useRefraction eliminates this complexity by making state inherently reactive.

When you change a refraction's value anywhere in your app, every component that uses that refraction automatically re-renders with the new data. It's like having a direct wire between your data and your UI.

lens.useRefraction

Since v1.0.0

Creates or connects to a reactive state value within a component.

Signature

const refraction = lens.useRefraction(initialValue | existingRefraction)

Parameters

initialValueT | Refraction<T>required

Initial value or existing refraction to connect to

Returns

Refraction<T>

Refraction object with .value property and .set() method

Example

// Create local refraction
const count = lens.useRefraction(0);

// Connect to global refraction
const theme = lens.useRefraction(globalTheme);

// Read value
console.log(count.value); // 0

// Update value
count.set(count.value + 1);

Comparison with Traditional Approaches​

Let's see how useRefraction compares to traditional state management:

React useState - Manual State Management
import React, { useState } from 'react';

const Counter = () => {
const [count, setCount] = useState(0);


// Need to manually manage multiple state pieces
const increment = () => {
setCount(prev => prev + 1);

};

return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
};

Issues with React useState:

  • Multiple useState calls for related data
  • Manual synchronization between state pieces
  • Easy to forget to update related state
  • No automatic reactivity across components

Basic Usage​

Simple State Management
 import { createComponent } from "refract";

const SimpleCounter = createComponent(({ lens }) => {
// Create local reactive state
const count = lens.useRefraction(0);
const message = lens.useRefraction("Hello, Refract!");

return (
<div>
<h2>{message.value}</h2>
<p>Count: {count.value}</p>

<button onClick={() => count.set(count.value + 1)}>
Increment
</button>

<button onClick={() => count.set(0)}>
Reset
</button>

<button onClick={() => message.set("Updated message!")}>
Change Message
</button>
</div>
);
});

Working with Objects​

Object State Management
const UserForm = createComponent(({ lens }) => {
// Object state
const user = lens.useRefraction({
name: "",
email: "",
age: 0,
preferences: {
theme: "light",
notifications: true
}
});

// Helper function for updating nested objects
const updateUser = (updates) => {
user.set({
...user.value,
...updates
});
};

const updatePreferences = (prefUpdates) => {
user.set({
...user.value,
preferences: {
...user.value.preferences,
...prefUpdates
}
});
};

return (
<form>
<input
type="text"
value={user.value.name}
onChange={(e) => updateUser({ name: e.target.value })}
placeholder="Name"
/>

<input
type="email"
value={user.value.email}
onChange={(e) => updateUser({ email: e.target.value })}
placeholder="Email"
/>

<input
type="number"
value={user.value.age}
onChange={(e) => updateUser({ age: parseInt(e.target.value) })}
placeholder="Age"
/>

<label>
<input
type="checkbox"
checked={user.value.preferences.notifications}
onChange={(e) => updatePreferences({ notifications: e.target.checked })}
/>
Enable notifications
</label>

<select
value={user.value.preferences.theme}
onChange={(e) => updatePreferences({ theme: e.target.value })}
>
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>

<div className="user-preview">
<h3>Preview:</h3>
<pre>{JSON.stringify(user.value, null, 2)}</pre>
</div>
</form>
);
});

Working with Arrays​

    const TodoList = createComponent(({ lens }) => {
const todos = lens.useRefraction([
{ id: 1, text: "Learn Refract", completed: false },
{ id: 2, text: "Build an app", completed: false }
]);

const newTodoText = lens.useRefraction("");

const addTodo = () => {
if (newTodoText.value.trim()) {
const newTodo = {
id: Date.now(),
text: newTodoText.value.trim(),
completed: false
};

// Always create new arrays for reactivity
todos.set([...todos.value, newTodo]);
newTodoText.set("");
}
};

const toggleTodo = (id) => {
todos.set(
todos.value.map(todo =>
todo.id === id
? { ...todo, completed: !todo.completed }
: todo
)
);
};

const deleteTodo = (id) => {
todos.set(todos.value.filter(todo => todo.id !== id));
};

const clearCompleted = () => {
todos.set(todos.value.filter(todo => !todo.completed));
};

return (
<div>
<div className="add-todo">
<input
type="text"
value={newTodoText.value}
onChange={(e) => newTodoText.set(e.target.value)}
onKeyDown={(e) => e.key === "Enter" && addTodo()}
placeholder="Add a new todo..."
/>
<button onClick={addTodo}>Add</button>
</div>

<div className="todo-list">
{todos.value.map(todo => (
<div key={todo.id} className={\`todo-item \${todo.completed ? 'completed' : ''}\`}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => toggleTodo(todo.id)}
/>
<span className="todo-text">{todo.text}</span>
<button onClick={() => deleteTodo(todo.id)}>Delete</button>
</div>
))}
</div>

<div className="todo-actions">
<p>Total: {todos.value.length} | Completed: {todos.value.filter(t => t.completed).length}</p>
<button onClick={clearCompleted}>Clear Completed</button>
</div>
</div>
);
});

Global State Connection​

Connect to global state using useRefraction:

Global State Store
import { createRefraction } from "refract";

// Global refractions
export const globalTheme = createRefraction("light");
export const globalUser = createRefraction(null);
export const globalNotifications = createRefraction([]);

When multiple components connect to the same global refraction, they all stay in sync automatically. Changes in one component immediately reflect in all others.