In this post, I will show you how to lift up information from one component to its parents in the hierarchy of the component tree.
First, let's start by the innermost component definition, where we have the information we want to lift up:
import React,{useState,useEffect} from 'react'
import * as styles from './index.module.css'
const Some=({liftUpInfo})=>{
const [value,setValue]=useState(false)
useEffect(()=>{
liftUpInfo.bind(null,setValue)()
},[])
return (
<div className={styles.general}>
{value&&'😄'}
{!value&&'ðŸ˜'}
</div>
)
}
export default Some
As you can see, we receive as props
a liftUpInfo
function. We use this function to effectively lift up information to the parent of the component. We use useEffect
hook to do so, binding the value or information we want to lift up in the call of the function.
Now let's see the definition of this liftUpInfo
function. To do so let's see the definition of the parent component:
import React,{useRef,useState,useEffect} from 'react'
import Some from '../Some'
import * as styles from './index.module.css'
const Other2=({liftUpInfo})=>{
const [foo,setFoo]=useState(false)
const information=useRef(null)
const catchInfo=(info)=>{
information.current=info
setFoo(prev=>!prev)
}
useEffect(()=>{
liftUpInfo.bind(null,information.current)()
},[])
return (
<div className={styles.general}>
<Some liftUpInfo={catchInfo}/>
</div>
)
}
export default Other2
So you see how the liftUpInfo
function in the child received as a prop
it's the catchInfo
function defined in the parent.
What this function does in the parent it's to update the value of a reference value. To do so we force a re-render of the component by setting its local state (foo
). After the re-render, the useEffect
hook takes in action and passes the info up to the next parent.
In the next parent we have exactly the same:
import React,{useEffect,useState,useRef} from 'react'
import * as styles from './index.module.css'
import Other2 from '../Other2'
const YetAnother=({liftUpInfo})=>{
const [foo,setFoo]=useState(false)
const information=useRef(null)
const catchInfo=(info)=>{
information.current=info
setFoo(prev=>!prev)
}
useEffect(()=>{
liftUpInfo.bind(null,information.current)()
},[])
return (
<div className={styles.general}>
<Other2 liftUpInfo={catchInfo}/>
</div>
)
}
export default YetAnother
Nothing to comment in here because it's exactly the same as before.
Now, finally, in the next component (parent), we will make use of the lifted information:
import React, { useRef,useState } from 'react'
import YetAnother from '../YetAnother'
import * as styles from './index.module.css'
const Any=()=>{
const [foo,setFoo]=useState(false)
const information=useRef(null)
const catchInfo=(info)=>{
information.current=info
setFoo(prev=>!prev)
}
const clicked=(setValue)=>{
setValue(prev=>!prev)
}
return (
<div className={styles.general}>
<YetAnother liftUpInfo={catchInfo}/>
<button className={'btn btn-primary'}
onClick={clicked.bind(null,information.current)}>change</button>
</div>
)
}
export default Any
This is the final result on the screen:
Now we are able to change the state of the innermost component in an event handler defined and handled in the outermost component.
Use of HOC
We can achieve the same result if we make use of a higher-order component. Let's define the next HOC:
import React, { useState,useRef } from 'react'
export default C=>(props)=>{
const [foo,setFoo]=useState(false)
const information=useRef(null)
const catchInfo=(info)=>{
information.current=info
setFoo(prev=>!prev)
}
return (
<C catchInfo={catchInfo} information={information} {...props}/>
)
}
As you can see we are generating the catchInfo
and information
props and passing them down to the component, with the rest of the props.
Let's show an example of the use of this HOC with the rest of the components redefined (except for Some
component, which remains the same):
import React,{useEffect} from 'react'
import * as styles from './index.module.css'
import withLiftUp from '../../hocs/withLiftUp'
import Some from '../Some'
const Other2Bis=({catchInfo,information,liftUpInfo})=>{
useEffect(()=>{
liftUpInfo.bind(null,information.current)()
},[])
return (
<div className={styles.general}>
<Some liftUpInfo={catchInfo}/>
</div>
)
}
export default withLiftUp(Other2Bis)
And the rest of the components redefined are:
import React,{useEffect} from 'react'
import * as styles from './index.module.css'
import withLiftUp from '../../hocs/withLiftUp'
import Other2Bis from '../Other2Bis'
const YetAnotherBis=({catchInfo,information,liftUpInfo})=>{
useEffect(()=>{
liftUpInfo.bind(null,information.current)()
},[])
return (
<div className={styles.general}>
<Other2Bis liftUpInfo={catchInfo}/>
</div>
)
}
export default withLiftUp(YetAnotherBis)
which is exactly the same as the previous one, and finally:
import React from 'react'
import * as styles from './index.module.css'
import withLiftUp from '../../hocs/withLiftUp'
import YetAnotherBis from '../YetAnotherBis'
const AnyBis=({catchInfo,information})=>{
const clicked=(setValue)=>{
setValue(prev=>!prev)
}
return (
<div className={styles.general}>
<YetAnotherBis liftUpInfo={catchInfo}/>
<button className={'btn btn-primary'}
onClick={clicked.bind(null,information.current)}>change</button>
</div>
)
}
export default withLiftUp(AnyBis)
With this, we get the same result as before.
Top comments (0)