Skip to content

Separation of concerns in React

Posted on:May 27, 2023 at 10:00 PM

As developers, we’re familiar with the experience of incorporating new features that result in an extensive display of code, seemingly endless. Regardless of whether you’re an experienced developer or just beginning your journey, this article aims to provide you with a comprehensive grasp of the concept of separation of concerns and its profound impact on your web and mobile development endeavours.

Separation of concerns is a practice of divide our code into more maintainable, reusable and testable separate sections or modules which is responsible for one single purpose, specific task.

The Power of Separation of Concerns

  1. Increase Cohesion
  2. Reduce Coupling
  3. Clean and Maintainable.
  4. Reusable across different parts of the application.
  5. Easy to test.
  6. Better code quality at all levels.

Overall, by using the separation of concerns in React, we can increase cohesion and reduce coupling, leading to a more maintainable and scalable codebase.

Let’s take an example of good “old-fashioned” Todo app.

import React, { useState } from "react";
import styles from "./Todo.module.scss";

const Todo = () => {
  const [taskName, setTaskName] = useState("");
  const [taskList, setTaskList] = useState([]);

  const onChangeTaskName = (event) => setTaskName(event.target.value);

  const onKeyDown = (event) => {
    if (event.key === "Enter") {
      onAddTask();
    }
  };

  const onAddTask = () => {
    const task = {
      id: Date.now(),
      name: taskName,
      isCompleted: false
    };
    setTaskList((tasks) => [...tasks, task]);
    setTaskName("");
  };

  const onComplete = (id) => {
    const tasks = taskList.map((task) => {
      if (task.id === id) {
        task.isCompleted = true;
      }
      return task;
    });
    setTaskList(tasks);
  };

  const onRemove = (id) => {
    const tasks = taskList.filter((task) => task.id !== id);
    setTaskList(tasks);
  };

  const disableAddButton = taskName.trim() === "";

  return (
    <div className={styles.container}>
      <div className={styles.innerContainer}>
        <input
          placeholder={"Enter task name"}
          className={styles.input}
          value={taskName}
          onChange={onChangeTaskName}
          onKeyDown={onKeyDown}
        />
        <button
          className={styles.button}
          disabled={disableAddButton}
          onClick={onAddTask}
        >
          {"Add Task"}
        </button>
      </div>
      <ul className={styles.list}>
        {taskList.map((task) => (
          <li key={task.id} className={styles.itemContainer}>
            <div className={styles.name}> {task.name} </div>
            <button
              disabled={task.isCompleted}
              className={styles.button}
              onClick={() => onComplete(task.id)}
            >
              {"Complete"}
            </button>
            <button className={styles.remove} onClick={() => onRemove(task.id)}>
              {"x"}
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default Todo;


While this simple Todo app may be easy to maintain in its current state, more complex logic and additional requirements could quickly make the codebase difficult to manage.

In such cases, even the most seasoned developers might hesitate to make changes, fearing that they’ll break something or unknowingly introduce bugs.

Solution

As our render function grows in size and complexity, it can become difficult to read and maintain. In order to improve code clarity and separation of concerns, it’s a good idea to split the render function into separate UI elements.

By doing so, we can compartmentalise different aspects of the UI and more easily make changes or updates. Additionally, this can lead to better code reusability and testability, as each UI element can be individually tested and reused in other components as needed.



We will explore some strategies and best practices for managing a complex app and keeping your codebase clean, maintainable, and bug-free.

Separate JSX File

Responsible for for displaying UI elements only.

We will create a Todo.jsx file that exclusively contains JSX elements.

Consider creating a separate function specifically for rendering the input, button and list elements,

Input Element

Button Element

List Element

We will split the todo item into separate component for improve maintainability.

Todo Item