State Variables
State variables are the “memory” of Components in our React application. These variables allow React components to manage and store data that changes over time.
Typing into the form should update the input field, clicking “next” on an image carousel should change which image is displayed, and clicking “buy” should put a product in the shopping cart. In these examples, the components need to “remember” things: the current input value, the current image, and the shopping cart. In React, this kind of component-specific memory is called a state. State in React
So as you already have seen, state variables are a crucial part of React, which provides interactivity to our application. So how do we define state variables?
Using State Variables in Functional Components
In Functional Components, we use HOOKS to hook into the superpowers that react gives us. In this case, we use the "useState” hook to declare the state variable. Let’s see it in action
import { useState } from "react";
const User = ({ name, email }: { name: string; email: string }) => {
const [count, setCount] = useState(1);
return (
<>
<div>
<p> Full Name: {name} </p>
<p> Email: {email} </p>
</div>
<div>
<h3>Current Level:{count}</h3>
<button onClick={() => setCount(count + 1)}>Increase level</button>
</div>
</>
);
};
export default User;
We use the useState() hook to define a state. The useState() returns a state variable and a setState dispatch action to update the state.
Inside the useState method, we provide an initial value which can be null, integer, string, object, array, or any other datatype. In this case, we set the initial value of the count to 1.
To access the state we use the state name directly, in this case, count.
Modifying the state requires us to use the setState method where we need to update the state value. As shown in the above example we use “setCount” to modify the state.
<button onClick={() => setCount(count + 1)}>Increase level</button>
Note: We cannot update the state directly by using count + 1.
Why?
Because doing so would bypass React's state management system and could lead to unpredictable behavior and rendering issues; essentially, we should treat the state as immutable and always create a new copy when updating it. And the “setState” dispatch action (setCount) does just that.
Key points about updating the state:
-
Immutability: React expects the state to be treated as immutable data, meaning you should not directly change the values within a state object.
-
setState function: To update the state, you must use the setState function (setCount in this case) which allows React to track changes and re-render the component accordingly.
Potential problems with direct modification:
-
No re-render: If you directly modify a state variable, React might not detect the change and won't re-render the component, leading to visual inconsistencies.
Question
We declare state variables like this.
const [count, setCount] = useState(1);
But in JavaScript, we cannot modify a constant so how is React assigning a new value to a constant?
Answer
When we update our state, the entire component is being re-rendered / re-initialized. Thus breaking the link between the previous value and the new value. This means that after the component is re-rendered/ re-initialized, the previous state variable which we had created using const is now no longer available and we now have a new instance of the state constant initialized with a new value.
Creating a new instance of the component means that there is no link between the old constant and the new constant thus enabling us to assign a new value to a constant.
Using State Variables in Class-Based Components
In class-based components, we define the state variables as an object inside the constructor. This object can be however big we want and React knows the given object is a state when we define it inside the “this.state” object. Let’s see it in action.
import React from "react";
class User extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 1,
};
}
render() {
return (
<>
<div>
<p> Full Name: {this.props.name} </p>
<p> Email: {this.props.email} </p>
</div>
<div>
<h3>Current Level:{this.state.count}</h3>
<button
onClick={() => this.setState({ count: this.state.count + 1 })}
>
Increase level
</button>
</div>
</>
);
}
}
export default User;
To access the count state we use “this.state.count”, this.state is the state object and count is the state variable that we recently defined. Same as getting the value of an object from its key.
To modify the state in class-based components, it is the same as in functional components where we do not modify the state directly but we use the setState method to modify the state variable.
<button onClick={() => this.setState({ count: this.state.count + 1 })} >
Increase Level
</button>
Here “this.setState” method takes an object, where the key is the state variable and then we modify the state here itself. To get the current state value, just like in the above scenarios we use “this.state” and update the state variable accordingly.
Now do you know why we cannot modify the state variables directly?
Click Here