React Graft

Turns a hook into a context: write the state once, read it anywhere below its provider.

Usage

Write a hook, pass it to createGraft, mount the provider, and read the value with use().

tsx
export const GraftLikes = createGraft({
  name: "GraftLikes",
  graft: useGraft,
});

function useGraft({ start = 0 }: { start?: number }) {
  const [value, setValue] = useState(start);
  const like = useCallback(() => setValue((count) => count + 1), []);

  return { value, like };
}

<GraftLikes.Provider start={10}>
  <LikeButton />
</GraftLikes.Provider>

const { value, like } = GraftLikes.use();

What you get

  • Typed props. The hook's options become the provider's props, and what it returns is what use() returns. Nothing to declare twice.
  • No empty context. The context itself is never exported, and use() throws, naming the graft, when it is called outside the provider.
  • A place for side effects. inject runs extra hooks inside the provider, like syncing the URL or saving to storage.

Limits

It is plain React: a hook, a provider and a context. No proxies and no selectors, so when the value changes, every component that reads it re-renders.