Skip to main content

Effects

1. Keep Effects Focused​

Each effect should have a single, clear purpose:

const UserDashboard = createComponent(({ lens, userId }) => {
const user = lens.useRefraction(null);
const posts = lens.useRefraction([]);
const notifications = lens.useRefraction([]);

// ✅ Good - separate effects for separate concerns

// Effect for fetching user data
lens.useEffect(() => {
fetchUser(userId).then(user.set);
}, [userId]);

// Effect for fetching posts
lens.useEffect(() => {
if (user.value) {
fetchUserPosts(user.value.id).then(posts.set);
}
}, [user.value?.id]);

// Effect for document title
lens.useEffect(() => {
if (user.value) {
document.title = \`\${user.value.name} - Dashboard\`;
}
}, [user.value?.name]);

return <div>Dashboard content</div>;
});

2. Minimize Dependencies​

Only include values that should actually trigger the effect:

  const SearchResults = createComponent(({ lens }) => {
const query = lens.useRefraction("");
const results = lens.useRefraction([]);
const loading = lens.useRefraction(false);

lens.useEffect(() => {
if (query.value.trim()) {
loading.set(true);
searchAPI(query.value)
.then(results.set)
.finally(() => loading.set(false));
} else {
results.set([]);
}
}, [query.value]);

3. Always Clean Up Resources​

Prevent memory leaks by cleaning up subscriptions, timers, and listeners:

Clean Up Resources
const ResourceManager = createComponent(({ lens }) => {
const data = lens.useRefraction(null);

lens.useEffect(() => {
// Set up multiple resources
const timer = setInterval(() => {
console.log('Timer tick');
}, 1000);

const abortController = new AbortController();

const handleResize = () => {
console.log('Window resized');
};

// Set up resources
window.addEventListener('resize', handleResize);

fetch('/api/data', { signal: abortController.signal })
.then(response => response.json())
.then(data.set);

// ✅ Clean up ALL resources
return () => {
clearInterval(timer);
abortController.abort();
window.removeEventListener('resize', handleResize);
};
}, []);

return <div>Component with managed resources</div>;
});

4. Handle Async Operations Safely​

Prevent race conditions and memory leaks with async operations:

Safe Async Operations
const AsyncDataComponent = createComponent(({ lens, dataId }) => {
const data = lens.useRefraction(null);
const loading = lens.useRefraction(false);
const error = lens.useRefraction(null);

lens.useEffect(() => {
let isCancelled = false;

const fetchData = async () => {
loading.set(true);
error.set(null);

try {
const response = await fetch(\`/api/data/\${dataId}\`);
const result = await response.json();

// ✅ Check if component is still mounted
if (!isCancelled) {
data.set(result);
loading.set(false);
}
} catch (err) {
if (!isCancelled) {
error.set(err.message);
loading.set(false);
}
}
};

fetchData();

// Cleanup function sets cancellation flag
return () => {
isCancelled = true;
};
}, [dataId]);

if (loading.value) return <div>Loading...</div>;
if (error.value) return <div>Error: {error.value}</div>;

return <div>{JSON.stringify(data.value)}</div>;
});