In this blog post, we will discuss how to interact with the state of your React components. The state is a crucial part of managing component data and handling user interactions.

Setting the Default State

To set the default state of a component, you need to initialize this.state in the constructor. For example, let’s consider a BlogPostExcerpt component with a clicked state:

class BlogPostExcerpt extends Component {
 constructor(props) {
 super(props);
 this.state = { clicked: false };
 }

 render() {
 return (
 <div>
 <h1>Title</h1>
 <p>Description</p>
 </div>
 );
 }
}

Accessing the State

To access the state, you can simply reference this.state.clicked within your component:

class BlogPostExcerpt extends Component {
 constructor(props) {
 super(props);
 this.state = { clicked: false };
 }

 render() {
 return (
 <div>
 <h1>Title</h1>
 <p>Description</p>
 <p>Clicked: {this.state.clicked}</p>
 </div>
 );
 }
}

Mutating the State

It’s important to note that you should never mutate the state directly by assigning values to this.state.clicked. Instead, always use the setState() method to update the state. Here’s an example:

this.setState({ clicked: true });

The setState() method takes an object as an argument, which can contain a subset or a superset of the state properties. Only the properties you pass will be mutated, while the others will remain unchanged.

Why You Should Always Use setState()

Using setState() is important because it allows React to track state changes. When you call setState(), React knows that the state has changed, and it triggers a series of events that eventually leads to the component being re-rendered, along with any necessary DOM updates.

Unidirectional Data Flow

In React, the state is always owned by a single component. Any data affected by this state can only affect components below it, i.e., its children. Modifying the state of a component will never impact its parent, siblings, or any other component in the application. This is known as “Unidirectional Data Flow.”

To share state between components, you need to move the state up to a common ancestor. While the closest ancestor is often the best place to manage the state, it’s not a strict rule. The state can be passed down to the components that require the value via props.

class Converter extends React.Component {
 constructor(props) {
 super(props);
 this.state = { currency: '€' };
 }

 render() {
 return (
 <div>
 <Display currency={this.state.currency} />
 <CurrencySwitcher currency={this.state.currency} />
 </div>
 );
 }
}

Moving the State Up in the Tree

To share state between components, you can move the state up the component tree. As per the Unidirectional Data Flow rule, if two components need to share state, the state needs to be moved up to a common ancestor. This allows multiple components to access and update the shared state.

In the following example, the Converter component manages the currency state, which is then passed down to its child components via props.

class Converter extends React.Component {
 constructor(props) {
 super(props);
 this.state = { currency: '€' };
 }

 handleChangeCurrency = () => {
 this.setState((prevState) => ({
 currency: prevState.currency === '€' ? '$' : '€'
 }));
 }

 render() {
 return (
 <div>
 <Display currency={this.state.currency} />
 <CurrencySwitcher
 currency={this.state.currency}
 handleChangeCurrency={this.handleChangeCurrency}
 />
 </div>
 );
 }
}

const CurrencySwitcher = (props) => {
 return (
 <button onClick={props.handleChangeCurrency}>
 Current currency is {props.currency}. Change it!
 </button>
 );
}

const Display = (props) => {
 return <p> Current currency is {props.currency}.</p>
}

In the Converter component, we define a handleChangeCurrency function that updates the currency state based on the current currency value. This function is then passed down to the CurrencySwitcher component as a prop, allowing it to mutate the state when triggered.

By following this pattern, you can efficiently manage and update the state of your React components, ensuring a smooth and maintainable application.