Lifting up information in React from one component to its parents in the component tree.
Tags: react
Published: 2020-09-13 16:43:32

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:

```javascript
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:

```javascript
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:

```javascript
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:

```javascript
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:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7k6vgvxsfg6tn5392qwb.png)

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*:

```javascript
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):

```javascript
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:

```javascript
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:

```javascript
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.