Framework Integration
Problem
You are using React, Vue, or Svelte and need to wire a Sourcerer source into your component's render cycle — subscribing to changes, triggering initial loads, and cleaning up on unmount.
Solution
Subscribe to the source in the appropriate component lifecycle hook for your framework. The source exposes a subscribe() method that returns an unsubscribe function. Call refresh() explicitly for remote sources to trigger the first fetch.
Local source
tsx
import { createLocalSource } from '@vielzeug/sourcerer';
import { useEffect, useMemo, useState } from 'react';
export function LocalUsers({ users }: { users: { id: number; name: string }[] }) {
const source = useMemo(() => createLocalSource(users, { limit: 10 }), [users]);
const [, rerender] = useState(0);
useEffect(() => source.subscribe(() => rerender((n) => n + 1)), [source]);
return (
<>
<input onChange={(e) => source.search(e.target.value)} />
{source.current.map((u) => (
<div key={u.id}>{u.name}</div>
))}
</>
);
}ts
import { createLocalSource } from '@vielzeug/sourcerer';
import { onUnmounted, ref } from 'vue';
const source = createLocalSource(users, { limit: 10 });
const tick = ref(0);
const stop = source.subscribe(() => {
tick.value += 1;
});
onUnmounted(stop);svelte
<script lang="ts">
import { onDestroy } from 'svelte';
import { createLocalSource } from '@vielzeug/sourcerer';
const source = createLocalSource(users, { limit: 10 });
let tick = 0;
const stop = source.subscribe(() => {
tick += 1;
});
onDestroy(stop);
</script>
{#each source.current as user}
<div>{user.name}</div>
{/each}Remote source
tsx
import { createRemoteSource } from '@vielzeug/sourcerer';
import { useEffect, useMemo, useState } from 'react';
export function RemoteIssues() {
const source = useMemo(
() =>
createRemoteSource({
fetch: ({ limit, page, search }) => api.issues.list({ limit, page, search }),
limit: 20,
}),
[],
);
const [, rerender] = useState(0);
useEffect(() => source.subscribe(() => rerender((n) => n + 1)), [source]);
useEffect(() => {
source.refresh();
}, [source]);
return <p>{source.meta.isLoading ? 'Loading...' : `${source.meta.totalItems} issues`}</p>;
}ts
import { createRemoteSource } from '@vielzeug/sourcerer';
import { onMounted, onUnmounted, ref } from 'vue';
const source = createRemoteSource({
fetch: ({ limit, page, search }) => api.issues.list({ limit, page, search }),
limit: 20,
});
const tick = ref(0);
const stop = source.subscribe(() => {
tick.value += 1;
});
onMounted(() => source.refresh());
onUnmounted(stop);svelte
<script lang="ts">
import { onDestroy, onMount } from 'svelte';
import { createRemoteSource } from '@vielzeug/sourcerer';
const source = createRemoteSource({
fetch: ({ limit, page, search }) => api.issues.list({ limit, page, search }),
limit: 20,
});
let tick = 0;
const stop = source.subscribe(() => {
tick += 1;
});
onMount(() => {
source.refresh();
});
onDestroy(stop);
</script>
<p>{source.meta.isLoading ? 'Loading...' : `${source.meta.totalItems} issues`}</p>Pitfalls
- Remote sources auto-fetch on creation by default (
autoFetch: true). If you subscribe in a lifecycle hook that runs after creation, the first fetch may already be in-flight. Callready()to wait for it, or setautoFetch: falseand triggerrefresh()explicitly from the mount hook. - Each component instance should create its own source (or share one via context/store); subscribing to a shared source that another component mutates can cause duplicate re-renders.
- In React, wrap
createLocalSource/createRemoteSourceinuseMemoto avoid recreating the source on every render.