How To Decouple Data from UI in React
Part 2: A further exploration of the Hooks, Render Props, and HOC patterns
In Part 1, I presented an approach to decouple the data fetching/management layer from a React component that renders some UI based on the data, which would free us from being locked into any particular data library or framework. Let’s call this Approach A.
Approach A. Custom Hook
Let’s create a custom hook — useSomeData
— that returns the properties someData
, loading
, and error
regardless of the data fetching/management logic. The following are 3 different implementations of useSomeData
.
With Fetch API and component state:
With Redux:
With Apollo GraphQL:
The 3 implementations above are interchangeable without having to modify this UI component:
But, as Julius Koronci correctly pointed out, while the data fetching/management logic is decoupled, the SomeComponent
UI is still coupled to the useSomeData
hook.
In other words, even though we can reuse useSomeData
without SomeComponent
, we cannot reuse SomeComponent
without useSomeData
.
Perhaps this is where Render Props and Higher Order Components do a better job at enforcing the separation of concerns (thanks again to Julius for highlighting this).
Approach B. Render Props
Instead of a custom hook that returns someData
, loading
, and error
, let’s create a Render Props component — SomeData
— that wraps around a function (i.e., children
needs to be a function), implements the data logic, and passes in someData
, loading
, and error
into the function.
You can replace line 4 in the snippet above with Redux, Apollo GraphQL, or any data fetching/management layer of your choice.
We can now reuse SomeComponent
(UI component) without SomeData
(Render Props component). We can also reuse SomeData
without SomeComponent
.
Approach C. Higher Order Components (HOC)
Let’s create a HOC — withSomeData
— that accepts a React component as an argument, implements the data logic, and passes someData
, loading
, and error
as props into the wrapped React component.
You can replace line 5 in the snippet above with Redux, Apollo GraphQL, or any data fetching/management layer of your choice.
We can now reuse SomeComponent
(UI component) without withSomeData
(HOC). We can also reuse withSomeData
without SomeComponent
.
Today I learned.
Which approach do you prefer and why?