Props and State

What is State in React ?

State of a component is an object that holds some information that may change over the lifetime of the component. We should always try to make our state as simple as possible and minimize the number of stateful components.

Let's create an user component with message state:
class User extends React.Component {
constructor(props) {
super(props);
this.state = {
message: 'Welcome to React world',
};
}
render() {
return (
<div>
<h1>{this.state.message}</h1>
</div>
);
}
}
Docusaurus

State is similar to props, but it is private and fully controlled by the component. i.e, It is not accessible to any component other than the one that owns and sets it.


How to set state with a dynamic key name?

If you are using ES6 or the Babel transpiler to transform your JSX code then you can accomplish this with computed property names.

handleInputChange(event) {
this.setState({ [event.target.id]: event.target.value })
}

What will happen if you use setState() in constructor?

When you use setState(), then apart from assigning to the object state React also re-renders the component and all its children. You would get error like this: Can only update a mounted or mounting component. So we need to use this.state to initialize variables inside constructor.


Is it good to use setState() in componentWillMount() method?

It is recommended to avoid async initialization in componentWillMount() lifecycle method. componentWillMount() is invoked immediately before mounting occurs. It is called before render(), therefore setting state in this method will not trigger a re-render. Avoid introducing any side-effects or subscriptions in this method. We need to make sure async calls for component initialization happened in componentDidMount() instead of componentWillMount().

componentDidMount() {
axios.get(`api/todos`)
.then((result) => {
this.setState({
messages: [...result.data]
})
})
}

Why should we not update the state directly?

If you try to update state directly then it won't re-render the component.

warning
//Wrong
this.state.message = 'Hello world';

Instead use setState() method. It schedules an update to a component's state object. When state changes, the component responds by re-rendering.

//Correct
this.setState({message: 'Hello World'});

Note: You can directly assign to the state object either in constructor or using latest javascript's class field declaration syntax.


What is Lifting State Up in React?

When several components need to share the same changing data then it is recommended to lift the shared state up to their closest common ancestor. That means if two child components share the same data from its parent, then move the state to parent instead of maintaining local state in both of the child components.


Why we need to pass a function to setState()?

The reason behind for this is that setState() is an asynchronous operation. React batches state changes for performance reasons, so the state may not change immediately after setState() is called. That means you should not rely on the current state when calling setState()β€Šsince you can't be sure what that state will be. The solution is to pass a function to setState(), with the previous state as an argument. By doing this you can avoid issues with the user getting the old state value on access due to the asynchronous nature of setState().

Let's say the initial count value is zero. After three consecutive increment operations, the value is going to be incremented only by one.

// assuming this.state.count === 0
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
// this.state.count === 1, not 3
If we pass a function to setState(), the count gets incremented correctly.
this.setState((prevState, props) => ({
count: prevState.count + props.increment,
}));
// this.state.count === 3 as expected

Why function is preferred over object for setState()?

React may batch multiple setState() calls into a single update for performance. Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.

This counter example will fail to update as expected:
warning
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});

The preferred approach is to call setState() with function rather than object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument.

// Correct
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment,
}));

What is the difference between setState() and replaceState() methods?

When you use setState() the current and previous states are merged. replaceState() throws out the current state, and replaces it with only what you provide. Usually setState() is used unless you really need to remove all previous keys for some reason. You can also set state to false/null in setState() instead of using replaceState().


How to listen to state changes?

The componentDidUpdate lifecycle method will be called when state changes. You can compare provided state and props values with current state and props to determine if something meaningful changed.

componentDidUpdate(object prevProps, object prevState)

Note: The previous releases of ReactJS also uses componentWillUpdate(object nextProps, object nextState) for state changes. It has been deprecated in latest releases.


What are the possible ways of updating objects in state?

  1. Calling setState() with an object to merge with state:

    • Using Object.assign() to create a copy of the object:

      const user = Object.assign({}, this.state.user, {age: 42});
      this.setState({user});
    • Using spread operator:

      const user = {...this.state.user, age: 42};
      this.setState({user});
  2. Calling setState() with a function:

    this.setState((prevState) => ({
    user: {
    ...prevState.user,
    age: 42,
    },
    }));

What is the recommended approach of removing an array element in React state?

The better approach is to use Array.prototype.filter() method.

For example, let's create a removeItem() method for updating the state.

removeItem(index) {
this.setState({
data: this.state.data.filter((item, i) => i !== index)
})
}

What are props in React?

Props are inputs to components. They are single values or objects containing a set of values that are passed to components on creation using a naming convention similar to HTML-tag attributes. They are data passed down from a parent component to a child component.

The primary purpose of props in React is to provide following component functionality:
  1. Pass custom data to your component.
  2. Trigger state changes.
  3. Use via this.props.reactProp inside component's render() method.
For example, let us create an element with reactProp property:
<Element reactProp={'1'} />

This reactProp (or whatever you came up with) name then becomes a property attached to React's native props object which originally already exists on all components created using React library.

props.reactProp

What will happen if you use props in initial state?

If the props on the component are changed without the component being refreshed, the new prop value will never be displayed because the constructor function will never update the current state of the component. The initialization of state from props only runs when the component is first created.

The below component won't display the updated input value:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
records: [],
inputValue: this.props.inputValue,
};
}
render() {
return <div>{this.state.inputValue}</div>;
}
}
Using props inside render method will update the value:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
record: [],
};
}
render() {
return <div>{this.props.inputValue}</div>;
}
}

Why you can't update props in React?

The React philosophy is that props should be immutable and top-down. This means that a parent can send any prop values to a child, but the child can't modify received props.


What are render props?

Render Props is a simple technique for sharing code between components using a prop whose value is a function. The below component uses render prop which returns a React element.

<DataProvider render={(data) => <h1>{`Hello ${data.target}`}</h1>} />

Libraries such as React Router and DownShift are using this pattern.


What is the purpose of callback function as an argument of setState()?

The callback function is invoked when setState finished and the component gets rendered. Since setState() is asynchronous the callback function is used for any post action.

Note: It is recommended to use lifecycle method rather than this callback function.

setState({name: 'John'}, () =>
console.log('The name has updated and component re-rendered'),
);

What is "key" prop and what is the benefit of using it in arrays of elements?

A key is a special string attribute you should include when creating arrays of elements. Key prop helps React identify which items have changed, are added, or are removed.

Most often we use ID from our data as key:
const todoItems = todos.map((todo) => <li key={todo.id}>{todo.text}</li>);
When you don't have stable IDs for rendered items, you may use the item index as a key as a last resort:
const todoItems = todos.map((todo, index) => <li key={index}>{todo.text}</li>);

Note:

  1. Using indexes for keys is not recommended if the order of items may change. This can negatively impact performance and may cause issues with component state.
  2. If you extract list item as separate component then apply keys on list component instead of li tag.
  3. There will be a warning message in the console if the key prop is not present on list items.

What is children prop?

Children is a prop (this.prop.children) that allow you to pass components as data to other components, just like any other prop you use. Component tree put between component's opening and closing tag will be passed to that component as children prop.

There are a number of methods available in the React API to work with this prop. These include React.Children.map, React.Children.forEach, React.Children.count, React.Children.only, React.Children.toArray.

A simple usage of children prop looks as below,
const MyDiv = React.createClass({
render: function () {
return <div>{this.props.children}</div>;
},
});
ReactDOM.render(
<MyDiv>
<span>{'Hello'}</span>
<span>{'World'}</span>
</MyDiv>,
node,
);

What is the purpose of using super constructor with props argument?

A child class constructor cannot make use of this reference until super() method has been called. The same applies for ES6 sub-classes as well. The main reason of passing props parameter to super() call is to access this.props in your child constructors.

Passing props:

class MyComponent extends React.Component {
constructor(props) {
super(props);
console.log(this.props); // prints { name: 'John', age: 42 }
}
}

Not passing props:

class MyComponent extends React.Component {
constructor(props) {
super();
console.log(this.props); // prints undefined
// but props parameter is still available
console.log(props); // prints { name: 'John', age: 42 }
}
render() {
// no difference outside constructor
console.log(this.props); // prints { name: 'John', age: 42 }
}
}

The above code snippets reveals that this.props is different only within the constructor. It would be the same outside the constructor.


How to apply validation on props in React?

When the application is running in development mode, React will automatically check all props that we set on components to make sure they have correct type. If the type is incorrect, React will generate warning messages in the console. It's disabled in production mode due to performance impact. The mandatory props are defined with isRequired.

The set of predefined prop types:
  1. PropTypes.number
  2. PropTypes.string
  3. PropTypes.array
  4. PropTypes.object
  5. PropTypes.func
  6. PropTypes.node
  7. PropTypes.element
  8. PropTypes.bool
  9. PropTypes.symbol
  10. PropTypes.any

We can define propTypes for User component as below:

import React from 'react';
import PropTypes from 'prop-types';
class User extends React.Component {
static propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number.isRequired,
};
render() {
return (
<>
<h1>{`Welcome, ${this.props.name}`}</h1>
<h2>{`Age, ${this.props.age}`}</h2>
</>
);
}
}

Note: In React v15.5 PropTypes were moved from React.PropTypes to prop-types library.


What is React proptype array with shape?

If you want to pass an array of objects to a component with a particular shape then use React.PropTypes.shape() as an argument to React.PropTypes.arrayOf().

ReactComponent.propTypes = {
arrayWithShape: React.PropTypes.arrayOf(
React.PropTypes.shape({
color: React.PropTypes.string.isRequired,
fontSize: React.PropTypes.number.isRequired,
}),
).isRequired,
};

What are the recommended ways for static type checking?

Normally we use PropTypes library (React.PropTypes moved to a prop-types package since React v15.5) for type checking in the React applications. For large code bases, it is recommended to use static type checkers such as Flow or TypeScript, that perform type checking at compile time and provide auto-completion features.


What is the difference between state and props?

Both props and state are plain JavaScript objects. While both of them hold information that influences the output of render, they are different in their functionality with respect to component. Props get passed to the component similar to function parameters whereas state is managed within the component similar to variables declared within a function.


What is the difference between super() and super(props) in React using ES6 classes?

When you want to access this.props in constructor() then you should pass props to super() method.

Using super(props):

class MyComponent extends React.Component {
constructor(props) {
super(props);
console.log(this.props); // { name: 'John', ... }
}
}

Using super():

class MyComponent extends React.Component {
constructor(props) {
super();
console.log(this.props); // undefined
}
}

Outside constructor() both will display same value for this.props.


How do you access props in attribute quotes?

React (or JSX) doesn't support variable interpolation inside an attribute value. The below representation won't work:

<img className="image" src="images/{this.props.image}" />

But you can put any JS expression inside curly braces as the entire attribute value. So the below expression works:

<img className="image" src={'images/' + this.props.image} />

Using template strings will also work:

<img className="image" src={`images/${this.props.image}`} />

Last updated on by krishnaUIDev