State and Props in React

State and Props in React

A few months ago we started a new project. We were used to work with Angular but this required something else. After some research we decided to use React.

React is a library for rendering views, it is not a complete framework like Angular. At the beginning, implementing a feature was difficult because the way react components interact. This is due to the fact that the interaction is a little different than we were used to. However, as time passes, the process becomes much easier and natural.

One of the difficulties we faced while working with React was understanding the interaction between State and Props. When either state or props change, the component is re-rendered. The biggest difference between them is that state is mutable data and props are immutable data that is inherited from the parent component.

The state is initialized on the component constructor and can change the value after the user interaction. Props are how components talk to each other. React has uni-directional data flow because props flow downwards from the parent component.

Here is an example of how react state and props work, the following snippets show how a list of users passes from the parent UserListContainer to the child User using props. Next, the child component display the user information.

				
					import React, { Component } from 'react';

import User from '../components/User';

export default class UserListContainer extends Component {
  render() {
    var users =[
      {
        "id": 1,
        "name": 'Megan',
        "surname": 'Coleman',
        "age":26,
        "country":'New Zealand'
      },
      {
        "id": 2,
        "name": 'Adam',
        "surname": 'Shaw',
        "age":30,
        "country":'Canada'
      }
    ]
    return (
      <section>
        {users.map((user) => {
          return(
            <User key={user.id} user={user} />
          )
        })
      }
      </section>
    );
  }
}
				
			

The first thing you notice is that React uses JSX for templating. It looks similar to HTML but there are some differences when working with JSX. Inside the code snippet we created a variable users and assigned it an array of dictionaries with user information. Afterwards, we loop through the users variable and pass each element to the User component through props.

Note: the key prop is necessary so React can keep the DOM changes to a minimum.

				
					import React, { Component } from 'react';

export default class User extends Component {
  constructor(props) {
    super(props);
    this.state = { detail: false};
    this.toggleDetail = this.toggleDetail.bind(this);
  }

  toggleDetail(){
    this.setState((prevState) => ({
      detail: !prevState.detail
    }))
  }

  render() {
    if(this.state.detail){
      return(
        <div>
          <p>{this.props.user.name} {this.props.user.surname}</p>
          <p>{this.props.user.age}</p>
          <p>{this.props.user.country}</p>
          <p onClick={this.toggleDetail}>see less</p>
        </div>
      )
    }
    return(
      <div>
        <p>{this.props.user.name} {this.props.user.surname}</p>
        <p onClick={this.toggleDetail}>see more</p>
      </div>
    )
  }
}
				
			

The User component receives the user information from the prop user. Next, using JSX braces syntax for specifying JavaScript code, we grab the user from the property by calling this.props.user. The User component renders different views depending on the local state detail. When the user clicks on see more or see less the component re-renders due to the state change and the if condition is re-evaluated.

In the example above setState receives an arrow function, because the new state depends on the previous one and setState is an asynchronous function, so that could cause unexpected errors. In the case that the new state is independent of the previous state, setState could receive an objects as an argument.

So the following code would not work properly

				
					  this.setState({
    detail: !this.state.detail
  })
				
			

This code is correct:

				
					  this.setState({
    name: "Joe"
  })
				
			

For more information about setState check out the official documentation.

You can also learn about our experience working with React Testing Library here.

See related posts