DEV Community

Cover image for ReactJS Component Pattern ~Single Responsibity Principle(SRP)~
Ogasawara Kakeru
Ogasawara Kakeru

Posted on

ReactJS Component Pattern ~Single Responsibity Principle(SRP)~

・This principle states that each component should have only one purpose, meaning it should focus on performing one task effectively. Adhering to SRP makes components easier to understand, test and maintain.

import React, { useEffect, useState } from 'react'

const URL = 'https://jsonplaceholder.typicode.com/todos'

export const App = () => {
  const [todos, setTodos] = useState([])

  useEffect(() => {
    const fetchAllTodos = async () => {
      const response = await fetch(URL)
      const allTodos = await response.json()
      setTodos(allTodos)
    }
    fetchAllTodos()
  }, [])

  return (
    <ul>
      {[...todos]
        .filter((todo) => todo.completed)
        .map((completedTodo) => (
          <li key={completedTodo.id}>
            <p>{completedTodo.id}</p>
            <a href="#">{completedTodo.title}</a>
          </li>
        ))}
    </ul>
  )
}

Enter fullscreen mode Exit fullscreen mode

This component has multiple responsibilities, as outlined below:

  • Fetching data
  • Compiling the fetched data
  • Rendering

Let's break it down into smaller components, each with a single responsibility.

import React, { useEffect, useState } from 'react'

const URL = 'https://jsonplaceholder.typicode.com/todos'

// Custom hook
export const useAllTodos = () => {
  const [todos, setTodos] = useState([])

  useEffect(() => {
    const fetchAllTodos = async () => {
      const response = await fetch(URL)
      const allTodos = await response.json()
      setTodos(allTodos)
    }
    fetchAllTodos()
  }, [])

  return { todos }
}

// Component
export const App = () => {
  const { todos } = useAllTodos()

  return (
    <ul>
      {[...todos]
        .filter((todo) => todo.completed)
        .map((completedTodo) => (
          <li key={completedTodo.id}>
            <p>{completedTodo.id}</p>
            <a href="#">{completedTodo.title}</a>
          </li>
        ))}
    </ul>
  )
}

Enter fullscreen mode Exit fullscreen mode

You can also extract the compilation function into a utility function.

// Util function
export const getCompletedTodos = (todos) => todos.filter((todo) => todo.completed)

// Component
export const App = () => {
  const { todos } = useAllTodos()

  return (
    <ul>
      {getCompletedTodos(todos).map((completedTodo) => (
        <li key={completedTodo.id}>
          <p>{completedTodo.id}</p>
          <a href="#">{completedTodo.title}</a>
        </li>
      ))}
    </ul>
  )
}

Enter fullscreen mode Exit fullscreen mode

Lastly, you can extract the To Do list function to the TodoItem.

// TodoItem
export const TodoItem = ({ todo }) => (
  <li>
    <p>{todo.id}</p>
    <a href="#">{todo.title}</a>
  </li>
)

export const App: React.FC = () => {
  const { todos } = useAllTodos()

  return (
    <ul>
      {getCompletedTodos(todos).map((completedTodo) => (
        <TodoItem key={completedTodo.id} todo={completedTodo} />
      ))}
    </ul>
  )
}
Enter fullscreen mode Exit fullscreen mode

This achieves the Single Responsibility Principle.

・Fetching data
・Compiling the fetched data
・Rendering
👇
・Fetching data(custom hook)
・Compiling the fetched data(util)
・Rendering(component)

Top comments (0)