HOC stands for Higher-Order Components.
It means a component which takes in another component and returns an enhanced component.
const HoC = Component => EnhancedComponent
The primary use case of HOC is to have a single place to sharing functionalities between components.
(Think of HOC more like a function, than component, this will be more clear as we go.)
Suppose, you have a requirement to calculate the innerWidth of browser viewport as it is resized and then do some computations/ui change.
For our example, we just want to display the window.innerWidth in "realtime".
To achieve this we can write a functional component and use the useEffect hook and attach a listener function which will update a state variable.
See code: https://github.com/abhidatta0/react-hoc-in-typescript/blob/master/src/ResizeComponent.tsx
Now, suppose we have to use this logic in another component.In that case, we have to duplicate our logic ๐ (which is obviously bad).
What could be a better(or best) way?
We can just abstract away this useEffect and listener code into another component and expose the innerWidth variable as a prop.
This "special" component is our Higher-Order Component.
withResize.tsx
const withResize = (Component: FC<any> )=> (props: any)=> {
const [innerWidth, setInnerWidth] = useState(0);
const handleResize = ()=>{
setInnerWidth(window.innerWidth);
}
useEffect(()=>{
window.addEventListener('resize', handleResize);
return ()=>{
window.removeEventListener('resize', handleResize);
}
},[]);
return <Component {...props} windowInnerWidth={innerWidth} />
}
WithResizeUsage.tsx
const WithResizeUsage = ({name, windowInnerWidth}: {name: string, windowInnerWidth: number})=>{
return (
<div>Inner Width is {windowInnerWidth} and name is {name}</div>
)
}
export default withResize(WithResizeUsage);
App.tsx
<WithResizeUsage name="Developer" />
Let's analyze what we have written
- In App.tsx, we call WithResizeUsage with a name prop.
- withResize is an hoc, which takes in a Component which itself accepts some props.
- The return of withResize is a component with all its original props and the extra
windowInnerWidth
prop. - In WithResizeUsage: we accept the
name
prop that we get from App.tsx and thewindowInnerWidth
that we get fromwithResize
hoc. - In WithResizeUsage, we wrap it with withResize in the last line
withResize(WithResizeUsage)
to bind it with withResize.
See code:
https://github.com/abhidatta0/react-hoc-in-typescript/blob/master/src/withResize.tsx
https://github.com/abhidatta0/react-hoc-in-typescript/blob/master/src/WithResizeUsage.tsx
Notice how clean our WithResizeUsage component becomes.
Let's look at how we can enhance the HOC a bit more.
Suppose, we need that that the displayed window.innerWidth is x amount more and x value will be configurable.If inner width is 90 and x is 3, we will display 93.
We will modify the HOC by adding another level to accept additional params.(This concept is called function currying)
withResizeAdvanced.tsx
type Params = {
bumped: number;
}
const withResizeAdvanced = (params: Params)=> (Component: FC<any> )=> (props: any)=> {
console.log(params);
const [innerWidth, setInnerWidth] = useState(0);
const handleResize = ()=>{
setInnerWidth(window.innerWidth+params.bumped);
}
useEffect(()=>{
window.addEventListener('resize', handleResize);
return ()=>{
window.removeEventListener('resize', handleResize);
}
},[]);
return <Component {...props} windowInnerWidth={innerWidth} />
}
withResizeAdvancedUsage.tsx
import withResizeAdvanced from "./withResizeAdvanced";
const WithResizeUsage = ({name, windowInnerWidth}: {name: string, windowInnerWidth: number})=>{
return (
<div>Inner Width is {windowInnerWidth} and name is {name}</div>
)
}
export default withResizeAdvanced({bumped: 5})(WithResizeUsage);
App.tsx
<WithResizeAdvancedUsage name="Developer"/>
Everything is similar to earlier HOC, except we can pass a object which has a property bumped
can we use to modify the innerWidth.
If we put earlier and the new component in App.tsx, we can visualize that for the later one, innerWidth is incremented by 5.
Github repo: https://github.com/abhidatta0/react-hoc-in-typescript
Note:
- Make sure HOC have the general logic (like getting window.innerWidth) will be reused across other components.
- An alternative to HOC pattern for function component is to use custom hooks.
Top comments (0)