Using Render Prop as Inversion of Control
Inversion of Control
Inversion of Control is a pattern where an application hands over some responsibility to the external parties. In React, the responsibility is delegated via props
At work, there was an improvement I need to make to the TimelineSelector
component , where I would like to update the Trigger Button to be a new Button component from the new Design System. The other UI components inside the TimelineSelector will remain using the old Design System for the time being.
As seen from the diagram above, in the monorepo package A, TimelineSelector
renders TimelineSelectorDropdown
from package B. However, I had to create the new Button from package A and pass it into TimelineSelectorDropdown
to avoid bleeding the new Design System library into package B before a full rollout plan.
In this case, we can’t simply just pass the Button component as a prop into the TimelineSelectorDropdown
because the the Button text was generated using complicated logics inside the TimelineSelectorDropdown
Class Component. It was difficult to share such logics using Hooks.
// this will not work as we need to pass Button text and onClick function
// from TimelineSelectorDropdown into the NewButton
<TimelineSelectorDropdown
button={<NewButton/> }
/>
Here, we can apply the Inversion of Control using the Render Prop pattern to delegate the responsibility of rendering the Button UI to TimelineSelector
and still make sure correct Button text is rendered by passing the text into the delegated Button UI.
In the render prop pattern, the TimelineSelectorDropdown
delegates the responosibility of rendering the Button UI out by accepting a prop
which takes in a function that returns the Button element. The prop can be any name such as render, children…etc.
we pass a rendering function as a prop
into the TimelineSelectorDropdown
. The rendering function will return the NewButton while also accepting additional information like toggle
, text
to supplement the Button UI rendering.
Often, we choose children
as the render prop! So we usually see render prop pattern implemented in the following manner.
Note
— I thought there will be no chance of using the Render Prop patterns after Hooks have become the popular way of sharing the logics between the components, but it is still very much needed when working with legacy code!
— Also, Render Props may have the added benefit of improving the performance of the app as it allows state to be shared with other siblings without lifting the state up and cause more components to re-render when state changes!
References
https://www.patterns.dev/react/render-props-pattern
Inversion of Control in React Youtube Video by Kent Dodds