---
# System prepended metadata

title: 'React: Lifting State'
tags: [React]

---

React: Lifting State
===
![](https://i.imgur.com/ZLirEbH.png)

###### tags: `React`

---
## What is Lifting state?

The most classic example of a lifting state would be **Accordion** component, usually a accordion has several panels, and use can click each of them, the basic behaviour is the panel expend one by one or close one when use expend another, if use expend one and others expend as well, it's not correct.

We know that we can store state to component, but when it needs to be controled like the example above, we should not store state in each panel, we need to move a level up to its parent component which is `Accordion`.

```
// Structure

|-- Accordion // pass props to each panel 
    |-- Panel 1
    |-- Panle 2
    |-- Panel 3
```

---
## Wrong behaviour

```typescript=
// Accordion.tsx
// Pass title and children down to Panel.tsx
import Panel from './Panel';

const Accordion = () => {
    return (
      <Panel title="Example 1">
        Lorem ipsum dolor sit, amet consectetur adipisicing elit. Beatae, vitae? Magnam cum blanditiis, voluptate quisquam voluptatum consequatur vel sunt ducimus unde sapiente! Eligendi, ullam aperiam sunt in exercitationem sit dolorem.
     </Panel>
       <Panel title="Example 2">
      Lorem ipsum dolor sit, amet consectetur adipisicing elit. Est totam beatae ullam qui adipisci corporis quisquam fugiat distinctio earum natus ipsa laborum modi molestiae, in ea et debitis cumque voluptates.
      </Panel>
    )
}

export default Accordion;
```

```typescript=
// Panel.tsx
// This is an uncontrolled component
import {useState} from "react"

// Define interface
interface IPanelProp {
  title: string;
  children: string;
} 

const Panel = ({title, children}: IPanelProp) => {
    // define a state to control active
    const [isActive, setIsActive] = useState<boolean>(false);
    
    return (
      <>
        <h3>{title}</h3>
        {isActive ? (
         <p>{children}</p>
         ) : (
           <button onClick={() => setIsActive(true)}>Expend</button>
         )}
      </>
    
    )
}

export default Panel;
```

We have made 2 panels with its own expend button.
![](https://i.imgur.com/lRQnM2t.png)

**The button will only update `isActive` state alone.** The example 1 is not able to collapse when I expend example 2, this is not the behaviour I want, the expected behaviour is that when example 2 expends and example 1 collapses and vice versa.
![](https://i.imgur.com/xzI99tS.png)

## Correct the behaviour

First of all, we need to lift all the states up to its parent component which is `Accordion`.

We use **index** to check which panel is active.

```typescript!
// Accordion.tsx
import {useState} from "react";
import Panel from "./Panel";

const Accordion = () => {
    const [activeIndex, setActiveIndex] = useState<number>(0);
    
    return (
      <Panel
        title="Example 1"
        isActvie={activeIndex === 0}
        onShow={() => setActiveIndex(0)}>
        Lorem ipsum dolor sit, amet consectetur adipisicing elit. Beatae, vitae?
        Magnam cum blanditiis, voluptate quisquam voluptatum consequatur vel
        sunt ducimus unde sapiente! Eligendi, ullam aperiam sunt in
        exercitationem sit dolorem.
      </Panel>
      <Panle 
        title="Example 1"
        isActvie={activeIndex === 1}
        onShow={() => setActiveIndex(1)}>
        Lorem ipsum dolor sit, amet consectetur adipisicing elit. Beatae, vitae?
        Magnam cum blanditiis, voluptate quisquam voluptatum consequatur vel
        sunt ducimus unde sapiente! Eligendi, ullam aperiam sunt in
        exercitationem sit dolorem.
      </Panel>
    
    )
}

export default Accordion;
```

```typescript!
// Panel.tsx

// Define type
interface IPanelProp {
  isActive: boolean
  title: string;
  children: string;
  onShow: () => void;
}

const Panel = ({isActive, title, children, onShow}: IPanelProp) => {
    return (
     <section>
      <h3>{title}</h3>
      {isActive ? <p>{children}</p> : <button onClick={onShow}>Expend</button>}
    </section>
  );
}

export default Panel;
```

---
## Controlled vs Uncontrolled component

[React doc](https://beta.reactjs.org/learn/sharing-state-between-components#controlled-and-uncontrolled-components)

## Colocate State
Colocate state in React means that we need to keep our “states” as close as where relevant is possible and let’s maintain/keep that practice that if we don’t nee some “state” is a component anymore then let’s just colocate that state where it needs to be.

[State Colocation will make your React app faster](https://kentcdodds.com/blog/state-colocation-will-make-your-react-app-faster)