Stateful and Stateless Components in React

Isabelle Letaconnoux
5 min readSep 26, 2017

--

React application are composed of ‘families’ components. Components allow you to divide the different responsibilities of your application into separate pieces. It can be difficult to determine what each component should do and how much they should be responsible for. A key step in learning react is understanding the difference between container components and presentational components, and which ones are responsible for managing state.

As a (very) general rule of thumb, your container components will be high level components. Some basic characteristic of container components are:

  1. Concerned with how things work
  2. Usually do not include any HTML markup — aside from wrapping divs around other components
  3. Manage state — they are STATEFUL
  4. Provide data (by storing it in their state and passing it as prop) and tell their ‘children’ how to behave (by passing callback functions as props)

Children components of container components are usually presentational components:

  1. Concerned with presenting data — how things look
  2. Usually are STATELESS — but not always
  3. Most likely a ‘child’ of a container component
  4. Will make up the majority of your application

As mentioned above, container components are stateful and presentational components are not. It can be helpful, however, to occasionally bend this rule.

I built a very basic To Do List application in order to demonstrate a couple of examples of when your application could benefit from a stateful presentational component. The file structure is as follows:

  1. TaskContainera stateful, container component, responsible for storing application data, defining functions on how the application will behave and passing those functions down to child components.

A. TaskForm — a stateful, presentational component, responsible for rendering form, gathering user input and does something with that input based on the props the parent container has passed down to it.

B. TaskList — a stateless, presentational component, responsible for iterating through the data to be rendered.

i. TaskItem — a stateful, presentational component, responsible for rendering tasks that have not yet been completed.

ii. CompletedTaskItem — a stateless, presentational component, responsible for rendering tasks that have been completed.

User input forms & controlled components:

The first example of a presentational component that is stateful is a UI form. The internal state of the TaskForm component is separate from the state of it’s parent component (TaskContainer), is set when it is first rendered and is updated based on the values that the user enters in the fields. The render function includes two input fields (one for the name of the task and another for the description):

render(){
return(
<form onSubmit={this.handleSubmit}>
<input type="text" placeholder="Item" onChange={this.handleTaskItemInput} value={this.state.inputTaskItem}/>
<input type="textarea" placeholder="Description" onChange={this.handleTaskDescriptionInput} value={this.state.inputTaskDescription}/>
<input type="submit" value="Create New Task"/>
</form>
)
}

Each of those fields includes an event listener ‘onChange’ that saves the value of the user input and updates the internal state using the setState() function. The event listener is listening for any change in the field, so the state is updated each time a character is entered in the field. For example:

handleTaskItemInput = (event) => {
this.setState({
inputTaskItem: event.target.value
})
}

When the user hits submit, the various input values have already been saved in the internal state of the form component and can be easily accessed to create a new task object. Additionally, controlled components allow for more validations and enforcing certain input formats.

Altering presentation based on a user action:

Another case in which it is helpful to make a presentational component stateful is when you need to alter how you are presenting data based on user input/actions. The TaskContainer state is as follows:

constructor(){super()this.state = {
tasksToDo: [ {item: "Trader Joe's", description: "Milk and Eggs", id: 1}, {item: "Laundry", description: "Sheets and Towels", id: 2}],
completedTasks: []
}
}

The state includes a key, tasksToDo, whose value is an array of task objects. Each object has an item, a description and an id. When rendered to the screen from the TaskItem component however, only the item is displayed:

In order to show the description of the task item, the user must click “show details”.

If the TaskItem component were a stateless component, we would have had to pass information all the way back to the parent component and then passed down updated props telling the TaskItem component how to change the display. This user action, however, is not changing anything outside this component — it is not altering the data that is stored in the TaskContainer state. By making this component stateful, we can handle these changes within this component in a much more efficient manner.

Here is a look at the code:

class TaskItem extends React.Component{
constructor(){
super();
this.state = {
detailsShowing: false

}
}
handleCompleteButton = () => {
this.props.onComplete(this.props.task)
}
handleShowDetails = () => {
this.setState({
detailsShowing: !this.state.detailsShowing
})
}
render(){
if (!this.state.detailsShowing){
return (
<li id={this.props.task.id}> {this.props.task.item}<button onClick={this.handleCompleteButton}>Done With Task</button> <button onClick={this.handleShowDetails}>Show Details</button></li>
)
} else {
return (
<li id={this.props.task.id}>{this.props.task.item}<button onClick={this.handleCompleteButton}>Done With Task</button> <button onClick={this.handleShowDetails}>Hide Details</button>
<ul>
<li>{this.props.task.description}</li>
</ul>
</li>
)
}
}
}

Clicking the ‘Show/Hide Details’ button simply changes the internal state of the TaskItem component which only affects the way the data is rendered.

If the user input or action changes the data or anything related to parent components, this should not be stored directly in the state (unless, like in a form, the it is then being passed back up to the parent through a prop that the parent passed down).

It is imperative to remember that the states of the presentational components are separate from that of the container component and the value of these states does not affect the main state. Essentially, the container component does not need to know about these states(if they did, then we wouldn’t make them states).

Sources:

https://toddmotto.com/stateful-stateless-components

https://facebook.github.io/react/docs/forms.html

--

--