React: Higher-Order Components
This time I get a sense of three use cases of React Higher-Order Components: wrapping with logs or so, shared logic on different components & same component with different data sources
higher-order component is a function that takes a component and returns a new component.
React: Higher-Order Components
Use case: Component wrapping
Let us say we have some component:
const SomeComp = ({value}) => { return <h1>{value}</h1> }
But we want to add some logs or hooks around it. We can wrap it with a higher-order component.
const withEffect = (Component,props) => { return class extends React.Component { componentDidMount() { console.log(props); } render() { return <Component {...props} /> } } }
Or as a functional component:
const withEffect = (Component,props) => { return () => { React.useEffect(()=>{ console.log(props) },[...props]) return <Component {...props} /> } }
And since it’s a function, implement it like this:
const App = ()=>{ const [someData,setSomeData] = React.useState({value:"hi"}); const CompWithEffect = withEffect(SomeComp,someData); React.useEffect(()=>{ setTimeout(()=>setSomeData({value:"hi dude"}),1000) },[]); return <> <CompWithEffect /> </> }
Use case: Shared logic
Let us say we have two different components with some shared logic. And I know, in this case, the simple solution is to pass the function, but allow me to use it as a simplistic example.
const RevertH1Comp = ({value}) => { const [revertValue,setRevertValue] = React.useState(''); React.useEffect(()=>{ setRevertValue(value.split('').reverse().join('')); },[value]); return <h1>{revertValue}</h1> } const RevertH2Comp = ({value}) => { const [revertValue,setRevertValue] = React.useState(''); React.useEffect(()=>{ setRevertValue(value.split('').reverse().join('')); },[value]); return <h2>{revertValue}</h2> }
We can extract the shared logic into a Higher-Order component:
const withRevert = (Component,props) => { return () => { const [newProp,setNewProp] = React.useState(props) React.useEffect(()=>{ setNewProp({...props, value: props.value.split('').reverse().join('')}); },[props.value]); return <Component {...newProp} /> } }
And be left with:
const RevertH1Comp = ({value}) => { return <h1>{value}</h1> } const RevertH2Comp = ({value}) => { return <h2>{value}</h2> }
Implementation:
const App = ()=>{ const [value,setValue] = React.useState({value:"hi"}); const H1CompWithEffect = withRevert(RevertH1Comp,value); const H2CompWithEffect = withRevert(RevertH2Comp,value); React.useEffect(()=>{ setTimeout(()=>setValue({value:"hi dude"}),1000) },[]); return <> <H1CompWithEffect /> <H2CompWithEffect /> </> }
Use case: Same component different usage
Now let’s say we have two different data sources:
const getSomeData = () => { return ["other","data"] } const getAsyncData = async () => { const timeout = (ms) => new Promise(resolve => setTimeout(resolve, ms)); await timeout(3000); return ["some","data"]; }
We want to display them using the same component:
const DisplaySomething = ({value}) => { return <>{value}</> }
Once more, here comes a Higher-Order component to the rescue:
const conect = (Component,getVal) => { return () => { const [value,setValue] = React.useState([]) React.useEffect(()=>{ (async ()=>{ const v = await getVal(); setValue(v); })(); },[]); return <Component value={value} /> } } const App = ()=>{ const SomeData = conect(DisplaySomething, getSomeData); const SomeAsyncData = conect(DisplaySomething, getAsyncData); return <> <SomeData /> <SomeAsyncData /> </> }
Summery
Soon I may play the gong as loudly as possible