ИТ-сообщество

На прошлой неделе я впервые посетил Frontend-конференцию, где один из спикеров рассказал о том, как успешно его команда перешла с Redux на Mobx. Главным преимуществом он назвал отсутствие шаблонности и ускорение разработки в полтора раза.

Я прочитал несколько статей и посмотрел другие отчеты, в которых все говорят, что Mobx лучше Redux. Возможно, это и так, но я не понимаю, почему всегда сравнивают Redux, а не Redux-Toolkit. Попробуем конструктивно посмотреть, действительно ли Mobx так хорош, как утверждают.

Основной аргумент последователей Mobx звучит так:

При разработке с помощью Redux вам необходимо написать шаблонный код, чтобы все работало. Вам нужно написать действия и селекторы.

В качестве примера напишем простейшую логику запроса постов и изменения счетчика и посмотрим, сколько строк кода мы сможем сэкономить.

import { makeAutoObservable } from "mobx";
import { IPromiseBasedObservable, fromPromise } from "mobx-utils";

/* Типизация */
const PostListSchema = z.object({
  id: z.number(),
  title: z.string(),
  description: z.string(),
  tag: z.string(),
  tags: z.array(z.string()),
  image: z.string(),
  progress: z.number(),
  progressTotal: z.number()
})

type PostListModel = z.infer<typeof PostListSchema>

/* Запрос на получение данных */
export const fetchPostList = async (limit: number) => {
  try {
    const response = await _api.get<PostListModel[]>(`api/posts`)

    if (!response.data) {
      throw new Error("Ошибка")
    }

    return response.data.data
  } catch {
    throw new Error("Ошибка")
  }
}


/* Создание стора */
class PostListStore {
    posts?: IPromiseBasedObservable<PostListModel[]>
    counter: 0

    constructor() {
        makeAutoObservable(this)
    }

    incrementCounter = () => {
      this.counter += 1
    }

    decrementCounter = () => {
      this.counter -= 1
    }

    fetchCoursesData = (limit: number) => {
        this.courses = fromPromise(fetchPostList(limit))
    }
}

export const postListStore = new PostListStore()

Теперь попробуем написать ту же логику в Redux-Toolkit. Но чтобы избежать предвзятости в нашей оценке, давайте попросим chatGPT написать за нас код.

import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { AppThunk } from "./store";
import { fetchPostList, PostListModel } from "./api";

/* Типизация */
interface PostListState {
  posts: PostListModel[] | null;
  loading: boolean;
  error: string | null;
  counter: number;
}

const initialState: PostListState = {
  posts: null,
  loading: false,
  error: null,
  counter: 0,
};

/* Создание слайса */
const postListSlice = createSlice({
  name: "postList",
  initialState,
  reducers: {
    incrementCounter(state) {
      state.counter += 1;
    },
    decrementCounter(state) {
      state.counter -= 1;
    },
  },
  extraReducers: (builder) => {
    builder
      .addCase(fetchPostList.pending, (state) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(fetchPostList.fulfilled, (state, action: PayloadAction<PostListModel[]>) => {
        state.loading = false;
        state.posts = action.payload;
      })
      .addCase(fetchPostList.rejected, (state, action) => {
        state.loading = false;
        state.error = action.error.message ?? "Ошибка";
      });
  },
});

export const { incrementCounter, decrementCounter } = postListSlice.actions;

export default postListSlice.reducer;

/* Запрос на получение данных */
export const fetchPostListAsync = (limit: number): AppThunk => async (dispatch) => {
  try {
    const response = await axios.get("/api/posts")

    if (!response.data) {
      throw new Error("Ошибка")
    }

    return response.data
  } catch {
    throw new Error("Ошибка")
  }
};

Реализация кода очень похожа, единственное, что в mobx кажется немного проще. Однако общая разница составляет 10 строк, я не могу назвать это шаблонным. Также нет необходимости записывать действия; набор инструментов делает все за нас.

ЧИТАТЬ   «Нет слов, какой позор»: жюри пришлось извиняться после обличения Барби на шоу «Маска»

В качестве эксперимента давайте попросимchatGPT написать компонент PostList, используя Mobx и Redux-Toolkit.

/* Код с использованием Mobx */

import React, { useEffect } from "react";
import { observer } from "mobx-react-lite";
import { postListStore } from "../stores/postListStore";
import { IPromiseBasedObservableState } from "mobx-utils";

const PostListMobX: React.FC = observer(() => {
  useEffect(() => {
    postListStore.fetchCoursesData(10); // Загружаем посты при монтировании компонента
  }, []);

  const { state } = postListStore.posts ?? {};

  switch (state) {
    case "pending":
      return <div>Loading...</div>;
    case "rejected":
      return <div>Error: Failed to fetch posts</div>;
    case "fulfilled":
      return (
        <div>
          {postListStore.posts?.value.map((post) => (
            <div key={post.id}>
              <h2>{post.title}</h2>
              <p>{post.description}</p>
              {/* Другие поля поста */}
            </div>
          ))}
        </div>
      );
    default:
      return null;
  }
});

export default PostListMobX;

Возможно, стоит отметить, что у GPT возникли проблемы с кодом Mobx, и правильный результат удалось получить только с четвертой попытки.

/* Код с использованием Redux-toolkit */

import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { RootState } from "../store";
import { fetchPostListAsync } from "../postListSlice";

const PostListRedux: React.FC = () => {
  const dispatch = useDispatch();
  const { posts, loading, error } = useSelector((state: RootState) => state.postList);

  useEffect(() => {
    dispatch(fetchPostListAsync(10)); // Загружаем посты при монтировании компонента
  }, [dispatch]);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;
  if (!posts) return null;

  return (
    <div>
      {posts.map((post) => (
        <div key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.description}</p>
          {/* Другие поля поста */}
        </div>
      ))}
    </div>
  );
};

export default PostListRedux;

Опять же, результат примерно такой же с точки зрения объема кода. Однако решение с использованием Redux-Toolkit кажется более простым.

На мой взгляд, даже сравнивать не-Toolkit версию с Mobx крайне странно. Я думаю, что это сравнение было актуально в 2020 году, возможно, но уж точно не в 2024 году. Со своей стороны, я все же сделаю вывод, что эти два инструмента не требуют от разработчика написания «тона» шаблонного кода.

ЧИТАТЬ   Раньше я сосредотачивался на том, чтобы ущипнуть копейку, но теперь я знаю, что это не секрет финансового процветания.

Source

От admin