DEV Community

Cover image for ReactJS SOLID Principle ~SRP (Single Responsibility Principle)~
Ogasawara Kakeru
Ogasawara Kakeru

Posted on

ReactJS SOLID Principle ~SRP (Single Responsibility Principle)~

In the context of React, this can be rephrased to mean that there should be only one reason to change a component or function.

Let's start by looking at some bad code to make it easier to understand.

import React, { useEffect, useState } from "react";
import axios from "axios";

type TodoType = {
  id: number;
  userId: number;
  title: string;
  completed: boolean;
};

export const TodoList = () => {
  const [data, setData] = useState<TodoType[]>([]);
  const [isFetching, setIsFetching] = useState(true);

  useEffect(() => {
    axios
      .get<TodoType[]>("https://jsonplaceholder.typicode.com/todos")
      .then((res) => {
        setData(res.data);
      })
      .catch((e) => {
        console.log(e);
      })
      .finally(() => {
        setIsFetching(false);
      });
  }, []);

  if (isFetching) {
    return <p>...loading</p>;
  }

  return (
    <ul>
      {data.map((todo) => {
        return (
          <li>
            <span>{todo.id}</span>
            <span>{todo.title}</span>
          </li>
        );
      })}
    </ul>
  );
};
Enter fullscreen mode Exit fullscreen mode

The TodoList component fetches Todo items and renders the UI based on the fetched data.
You may occasionally come across components like this in projects, but they violate the Single Responsibility Principle (SRP) for the following reasons.

The same component handles two responsibilities: fetching data and rendering the TODO list.

For example, if the endpoint specified in the fetch section changes, you would have to modify the contents of the TodoList component. Similarly, if you want to change the title’s styling, you would also need to modify this component.
Since there are multiple reasons why this component might need to be changed, it’s important to properly separate its responsibilities. Fortunately, in React, you can use custom hooks to separate the fetching logic from the component’s rendering, so we’ll extract the fetching logic into a custom hook.

import React, { useEffect, useState } from "react";
import axios from "axios";

type TodoType = {
  id: number;
  userId: number;
  title: string;
  completed: boolean;
};

export const useFetchTodo = () => {
  const [data, setData] = useState<TodoType[]>([]);
  const [isFetching, setIsFetching] = useState(true);

  useEffect(() => {
    axios
      .get<TodoType[]>("https://jsonplaceholder.typicode.com/todos")
      .then((res) => {
        setData(res.data);
      })
      .catch((e) => {
        console.log(e);
      })
      .finally(() => {
        setIsFetching(false);
      });
  }, []);

  return {
    todo: data,
    isFetching,
  };
};

export const TodoList = () => {
  const { todo, isFetching } = useFetchTodo();

  if (isFetching) {
    return <p>...loading</p>;
  }

  return (
    <ul>
      {todo.map((todo) => {
        return (
          <li>
            <span>{todo.id}</span>
            <span>{todo.title}</span>
          </li>
        );
      })}
    </ul>
  );
};
Enter fullscreen mode Exit fullscreen mode

By doing this, the component no longer needs to know the specifics of the fetching process; it only needs to be aware of the interface. For example, even if you later need to add error handling to the fetch process, you can simply modify useFetchTodo without changing the component itself.

Top comments (0)