
You might’ve heard about Lifting Your State hundreds of times before but have really been unable to comprehend what does it actually mean, neither do I.
So, I looked up the official docs and it says- Often, several components need to reflect the same changing data. We recommend lifting the shared state up to their closest common ancestor.
Let’s understand this with a simple example.
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class Counter extends React.Component {
state = {
counter: 0
};
decrement = () => {
this.setState({ counter: this.state.counter - 1 });
};
increment = () => {
this.setState({ counter: this.state.counter + 1 });
};
render() {
return (
<>
<button type="button" onClick={this.decrement}>
-
</button>
{this.state.counter}
<button type="button" onClick={this.increment}>
+
</button>
</>
);
}
}
class App extends React.Component {
render() {
return (
<div className="App">
<Counter />
<p>You have clicked 0 times!</p>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);First off, we have a Counter component. This component has the state initialized with a value of counter set to zero. Also, we have increment and decrement methods. The output would something look like this.
Now, we want “You clicked 0 times” to increment on clicking the button. In order to do that, could we do add clicks: 0 field in Counter like this and pass this data in state to the App component ? I don’t see any other solution.
class Counter extends React.Component {
state = {
counter: 0,
clicks: 0
};
////
////
class App extends React.Component {
render() {
return (
<div className="App">
<Counter />
<p>You have clicked 0 times!</p> // how do I update this ?
</div>
);
}
}Well, I don’t think that’s quite possible.
So, the solution would be lift the state up. Instead of keeping the state in Counter, we move the state to our App component. See here.
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class Counter extends React.Component {
render() {
const { increment, counter, decrement } = this.props;
return (
<>
<button type="button" onClick={decrement}>
-
</button>
{counter}
<button type="button" onClick={increment}>
+
</button>
</>
);
}
}
class App extends React.Component {
state = {
clicks: 0,
counter: 0
};
decrement = () => {
this.setState({
counter: this.state.counter - 1,
clicks: this.state.clicks + 1
});
};
increment = () => {
this.setState({
counter: this.state.counter + 1,
clicks: this.state.clicks + 1
});
};
render() {
const { clicks, counter } = this.state;
return (
<div className="App">
<Counter
increment={this.increment}
decrement={this.decrement}
counter={counter}
/>
<p>You have clicked {clicks} times!</p>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);Now, the funny part is, you might’ve done this unknowingly before or you’d consider this approach to be the general way of doing it. I totally agree with you, but yeah, that’s the whole lifting state up fuzz is. Even the docs definition would make some sense now.
Try the CodeSandBox here.
Thank You for reading this article. Follow me on Twitter for more updates.