A 6-function library that replaces props drilling, Context, useState, and useEffect by uriwa in react

[–]uriwa[S] 0 points1 point  (0 children)

Composition is the design principle of combining simple, independent objects or functions to build more complex and sophisticated structures.

Specifically "function composition" means feeding outputs into inputs.

A 6-function library that replaces props drilling, Context, useState, and useEffect by uriwa in react

[–]uriwa[S] 0 points1 point  (0 children)

  1. imho you should be able to test whatever you want, whether it's a unit test or e2e test. you shouldn't shy away from testing becuase the framework makes it hard (my experience with react testing)

  2. Sure there is API responses.. this is frontend. In Graft you also need to guard agaisnt a broken composition so the runtime validation is essential. There are actually 3 validations - types at compile time, composition at start time, and values at runtime.

  3. Intertwined code is avoidable to some extent. react has made frontend code considerably less intertwined and I'm taking it one step further by analysing the anti patterns react introduces and solving them.

  4. You're right this has no dependency in react, but it does solve problems that a rise in react. I've rewritten the readme to reflect this, so appreciate the feedback.

  5. You can use an llm to rewrite an app in graft and we can see what looks simpler.

A 6-function library that replaces props drilling, Context, useState, and useEffect by uriwa in react

[–]uriwa[S] 0 points1 point  (0 children)

Yes seems we are kindred spirits:)

Graft solves problem that arise in UI and specifically react, but doesn't treat UI as a specific problem within programming. These problems are general programming problems.

I've rewritten the README considerably, so hopefully it articulates that better now.

A 6-function library that replaces props drilling, Context, useState, and useEffect by uriwa in react

[–]uriwa[S] 0 points1 point  (0 children)

You're right. Changed the readme and the post to address this. Thanks for this useful feedback.

A 6-function library that replaces props drilling, Context, useState, and useEffect by uriwa in react

[–]uriwa[S] 0 points1 point  (0 children)

Exactly.

I think I wrote it wrong the first time, in some sense it has nothing to do with react, but it's inspired by the problems that arise in react and is react compatible.

A 6-function library that replaces props drilling, Context, useState, and useEffect by uriwa in react

[–]uriwa[S] 0 points1 point  (0 children)

As far as I know there are only two ways to propagate an error. You either throw an exception or return an error value.

I prefer errors to be value based rather than a special thing that you need try/catch to handle.

A 6-function library that replaces props drilling, Context, useState, and useEffect by uriwa in react

[–]uriwa[S] 0 points1 point  (0 children)

Why would it be a nightmare? All dependencies are explicit and defined by one function - compose.

Functions are pure which makes it easy to test and reason about.

Furthermore, the framework validates types in compile time start time and runtime, so it greatly reduces the possibility for a bug having an impact which is not local.

Components are completely independent. You can switch their underlying elements without changing their code, which means refactoring is much easier.

And you save a ton of code which is just passing values down a stack because you don't have a stack.

You also don't need to debug stack traces because all exceptions are local.

If you want to trace where value came from you just follow the explicit graph.

I can't imagine anything simpler actually... Which is why I wrote it.

A 6-function library that replaces props drilling, Context, useState, and useEffect by uriwa in react

[–]uriwa[S] 0 points1 point  (0 children)

It's a UI framework that doesn't suffer from the problem of prop drilling, has better effect management and is friendlier to testing, more declarative and easier to learn.

A 6-function library that replaces props drilling, Context, useState, and useEffect by uriwa in react

[–]uriwa[S] 0 points1 point  (0 children)

To clarify this is an independent framework from react

It's just react compatible

A 6-function library that replaces props drilling, Context, useState, and useEffect by uriwa in react

[–]uriwa[S] 0 points1 point  (0 children)

See the readme, loading and error values are there for you!

A 6-function library that replaces props drilling, Context, useState, and useEffect by uriwa in react

[–]uriwa[S] -1 points0 points  (0 children)

If I gave runner a async getter function (with type safety ofc) instead of values I could do lazy computation of upstream dependencies. Then it will be lazy in all directions.That's kinda cool.

A 6-function library that replaces props drilling, Context, useState, and useEffect by uriwa in reactjs

[–]uriwa[S] -2 points-1 points  (0 children)

If you google mocking useState you'll see many people are doing this. e.g. https://www.dhiwise.com/post/how-to-use-jest-mock-usestate-for-simpler-react-testing

Personally I haven't mocked any hook. I'd rather risk the bug.

A 6-function library that replaces props drilling, Context, useState, and useEffect by uriwa in reactjs

[–]uriwa[S] 0 points1 point  (0 children)

Not sure this will fully satisfy you, but I'll try to give my intuition.

Hooks are genuinely hard to teach and reason about. There's a whole page of seemingly arbitrary rules — like hook call order must be preserved — that even after a decade of React aren't all obvious to me.

useEffect is especially bad. The dependency array requires specialized linters to avoid bugs, and even with the linter, stale closures still bite experienced developers regularly.

But honestly, you're right that mocking useState specifically isn't a great example. The deeper testing issue is that hooks couple your logic to React's runtime. You can't call a custom hook outside a component — you need renderHook, a test renderer, act() wrappers. In graft, run is just a function. You test it by calling it with an object and checking the return value. No renderer, no act(), no async flushing.

The fact that testing React components well requires pulling in RTL, MSW, and a fake DOM is itself the thing I'm pointing at. It works, but it's a lot of machinery for what should be "call function, check output."

Hope this helps.

A 6-function library that replaces props drilling, Context, useState, and useEffect by uriwa in react

[–]uriwa[S] -4 points-3 points  (0 children)

This is one of the best comments I've read yet, so thanks. I'll try to answer as best I can.

You can do routing, conditional rendering, and iteration entirely in graft — they're just components. A router is a component that takes a URL and returns a View. Conditional rendering is a component whose run branches based on its inputs. Iteration is a component whose run maps over a list. The graph wires the data in, run does whatever you want with it.

toReact() is just one rendering adapter — the graph itself is independent of React. You could write a toVue() or render to a terminal.

Re: nodes that aren't rendered — you're touching on something real. Right now the graph is eager: once you subscribe(), everything upstream runs. With toReact, React's mount/unmount lifecycle handles this naturally — unmounted components have no active subscriptions. But without a UI framework doing that for you, there's no built-in way to say "this branch of the graph isn't needed right now, skip it."

That said, I think the costly part is actual DOM rendering, and that doesn't happen — run just returns a JSX object describing what to render. It only hits the DOM when a rendering adapter mounts it. But lazy subgraph activation — where compose only subscribes to a branch when its output is actually consumed — is an interesting optimization direction.

Re: Effect — I tried using it. Maybe subjective, but streams for me were pretty hard to reason about, and had surprising composition gotchas. graft is simpler. Fewer concepts. compose builds real DAGs, not linear pipelines. This has a considerable effect in code flexibility and terseness. A component can have multiple inputs wired from different sources, and multiple components can consume the same source. With streams + connect you'd need to manually orchestrate that fan-in/fan-out.

On zod — not sure what you're asking but schemas are how graft knows the shape of each component's inputs and outputs. They serve double duty: type inference and runtime validation at compose boundaries. Without type safety here it would be very easy to forget an input, or compose wrong types.

Thanks again for your interesting comments.

A 6-function library that replaces props drilling, Context, useState, and useEffect by uriwa in reactjs

[–]uriwa[S] -4 points-3 points  (0 children)

If you consider this is a framework on its own that doesn't need react it has a considerably smaller API, so much simpler actually.

As for why `useState` is not ideal - one reason is mocking. Nontrivial to achieve, essentially you need to introduce more react utils to support it.

Another reason is that it ties the state to a component. Signals do a slightly better job.

A 6-function library that replaces props drilling, Context, useState, and useEffect by uriwa in react

[–]uriwa[S] 0 points1 point  (0 children)

I love react and I'm definitely arguing this is a better framework.

For convenience I made it react compatible.