1. 程式人生 > >Epitath: In memoriam Render Props and HOCs

Epitath: In memoriam Render Props and HOCs

Epitath: In memoriam Render Props and HOCs

Reusability is a must in React world, after mixins were considered harmful two big approaches got in to the scene: Render Props and HOCs.

Both created a lot of discussion about their limitations in the community. Render Props greatly avoid indirection but fail a bit in composability — although

you can use something likeyou still can’t have a more explicit way to pass the props each Render Props take or not render another Render Props before you get a value from a previous one without adding some more boilerplate –and function HOCs have a great composability but fail in too much indirection. “Tradeoffs” one may say. But what if we could come up with a third way that would bring together the best from these approaches?

But what if we could come up with a third way that would bring together the best from these approaches?

“How did you come up with this? Is this a new approach?”

The click for us came when we realized that this

<Query>  {({ data }) =>    <Mutation>      {({ mutate, result }) =>        <Form>         {({ values, handleChange }) => { ad infinitum }}        </Form>      }    </Mutation>  }</Query>

Does not just recalls but it is a callback hell, which in other words, would allow us to do some kind of CPS. Like async and await. If you want to take a look on CPS concept ramifications take a look on this ReasonML thread about adding a CPS sugar.

“How’s this different from React Suspense?”

Different from React Suspense which throws a promise, evaluate it and give you back the result once, you can still render more than once but you gotta add some boilerplate of your own. Also, in the end Suspense has a very different goal, which is to hold rendering meanwhile you do some async work to not give the user an inpatient loading right away. With Epitath you can write Render Props with the ease of an imperative API, which means you can potentially build your own Suspense API from scratch with it or just use now without needing to change nothing in the internals of your Render Props.

“Can I use it with my current HOCs and Render Props based components?”

YES!

“So, what wizardry have you done to make this work?”

With the flexibility of JS immutable generators.

Wait, you said “immutable generators”? What?

Generators in JS by default keep their own machine state and once you invoke it keeps that state and changes when you call .next. And that’s a problem for our case. Why? When wrapping one childrencallback into another any re-render from a Render Prop would cause the callback to pick up from where it left and call .next again causing the machine state of the generator to move and creating inconsistence. So we used immutagen to simulate an immutable generator from a mutable one. The whole code is 21 LOC, including line breaks. No magic:

Thus, by leveraging generators power we can even use try-catch and other top level JS structures ?. Take a look in these experiments Gabriel Takashi Katakura did with it

Try catch

ErrorBoundary + Async Timer + Normal Render Prop

As you can see you can plug possibly anything. Observables, promises, etc.

“What’s next for it?”

Well, we are using it already at Astrocoders projects when we are not at ReasonReact fantasy land. Though we are delivering this as a proposal for the whole React community to think in a easier and, more importantly, human readable way to write and maintain async code.

We hope that it’ll be a proposal for the whole React community to think in easier and, more importantly, human readable way to write and maintain async code.