DEV Community

Cover image for ReactJS SOLID Principle ~ DIP (Dependency Inversion Principle)~
Ogasawara Kakeru
Ogasawara Kakeru

Posted on

ReactJS SOLID Principle ~ DIP (Dependency Inversion Principle)~

・The dependency that imports an extra module should depend on the abstract interface, but not the concrete one.

Because this makes it easy to modify the application, while an application that depends on a concrete interface might collapse immediately.

Here is an example using the swr.

import useSWR from 'swr'

const fetcher = async (url) => {
  const res = await fetch(url)
  return res.json()
}

export const Todo = () => {
  const { data } = useSWR('https://jsonplaceholder.typicode.com/todos', fetcher)

  if (!data) 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 snippet above has several issues.

・Fetches data within the Todo component.
・The Todo component depends on the concrete interface.

Let's consider if we convert the swr to the react-query that provides superior functionality than swr. Can we do it easily?

Here are several issues.

・Variety of components depends on the swr directly. We are bound to replace it in every component.

・If each component has its own different errors, we have to fix them.

And other issues exist in the application.

Let's deal with the issue by applying the DPI to direct the dependency to the interface.

import useSWR from 'swr'

interface IUseFetch<T> {
  key: string
  fetcher: () => Promise<T>
}

interface IResponse<T> {
  data: T | undefined,
  error: string | undefined
  isValidating: boolean
}

export const useFetch = <T>({ key, fetcher }: IUseFetch<T>): IResponse<T> => {
  const { data, error, isValidating } = useSWR<T, string>(key, fetcher)

  return {
    data,
    error,
    isValidating
  }
}
Enter fullscreen mode Exit fullscreen mode
import { useFetch } from './useFetch'

type ResponseType = {
  id: number
  title: string
}

const fetcher = async (): Promise<ResponseType[]> => {
  const url = 'https://jsonplaceholder.typicode.com/todos'
  const res = await fetch(url)
  return res.json()
}

export const Todo = () => {
  const { data } = useFetch<ResponseType[]>({ key: '/todos', fetcher })

  if (!data) 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

Above codes, we defined useFetch hook to wrap the swr, and call it from the Todo component.

In this case, we have only to modify the useFetch hook if we apply the react-query in the application.

Top comments (0)