Mastering Large-Scale React State Management with MobX

Getting Started

To begin, create a TypeScript React app using create-react-app. Install the necessary dependencies, including MobX, and delete unnecessary files. We’ll build a simple blog app with three entities: users, posts, and comments.

npx create-react-app my-app --template typescript
npm install mobx mobx-react

Defining Entity Types

Create types for each entity in a types folder under src. For example, user.ts would contain the user type definition.

// src/types/user.ts
export interface User {
  id: number;
  name: string;
  email: string;
}

Next, create types for posts and comments.

// src/types/post.ts
export interface Post {
  id: number;
  title: string;
  content: string;
  userId: number;
}
// src/types/comment.ts
export interface Comment {
  id: number;
  content: string;
  postId: number;
}

The App Store

Create a folder called stores under src and define the app store in app.ts. This file will contain all the stores of the app. For now, make it an empty class.

// src/stores/app.ts
export class AppStore {}

Creating Models

Create a folder called models under src and implement the models for each entity. Each model will implement the corresponding type and define relationships with other entities.

// src/models/user.ts
import { User } from '../types/user';
import { AppStore } from '../stores/app';

export class UserModel {
  private appStore: AppStore;
  private user: User;

  constructor(appStore: AppStore, user: User) {
    this.appStore = appStore;
    this.user = user;
  }

  // Define relationships and methods here
}

Creating Stores in MobX

Create stores for each entity, starting with the user store.

// src/stores/userStore.ts
import { observable, action } from 'obx';
import { UserModel } from '../models/user';

export class UserStore {
  @observable users: UserModel[] = [];

  @action
  load(): void {
    // Load data into the store
  }

  get allUsers(): UserModel[] {
    return this.users;
  }
}

Defining Relationships

Define relationships between models. For example, the user model will have many posts, which can be coded as a computed property derived from the post store.

// src/models/user.ts
import { PostModel } from './post';

export class UserModel {
  //...

  get posts(): PostModel[] {
    return this.appStore.postStore.allPosts.filter((post) => post.userId === this.user.id);
  }
}

Coding the Network Layer

Create an AppApi class to handle network calls and load data into stores. Separate the network layer from the stores, so the store doesn’t know where the data is loaded from.

// src/api/appApi.ts
import axios from 'axios';

export class AppApi {
  private apiUrl: string;

  constructor(apiUrl: string) {
    this.apiUrl = apiUrl;
  }

  loadUsers(): Promise<user[]> {
    return axios.get(`${this.apiUrl}/users`);
  }

  // Create API clients for each resource
}</user[]>

App Context

Use React Context to provide the store and API to components.

// src/context/appContext.ts
import { createContext, useState } from 'eact';
import { AppStore } from '../stores/app';
import { AppApi } from '../api/appApi';

interface AppContext {
  store: AppStore;
  api: AppApi;
}

const AppContext = createContext({ store: new AppStore(), api: new AppApi('https://api.example.com') });

export default AppContext;

Using Components with MobX

Create components for each page, such as the home page, post page, and user page. Use the useAppContext hook to get the store and API, and wrap components with observer from mobx-react to observe changes to observables from the store.

// src/components/HomePage.tsx
import React from 'eact';
import { observer } from 'obx-react';
import { useAppContext } from '../context/appContext';

const HomePage: React.FC = () => {
  const { store, api } = useAppContext();

  // Use the store and API here
  return (

  );
};

export default observer(HomePage);

Building Pages

Create pages for the app, such as the home page, post page, and user page. Use the useAppContext hook to get the store and API, and load data into the store using the API clients.

// src/pages/HomePage.tsx
import React, { useEffect } from 'eact';
import { useAppContext } from '../context/appContext';

const HomePage: React.FC = () => {
  const { store, api } = useAppContext();

  useEffect(() => {
    api.loadUsers().then((users) => store.userStore.load(users));
  }, [store, api]);

  // Use the store and API here
  return (

  );
};

The Root App Component

Create the root app component, App.tsx, to instantiate the store and API, and provide it to the app through AppContext.Provider. Use BrowserRouter from react-router-dom to render pages.

// src/App.tsx
import React from 'eact';
import { BrowserRouter } from 'eact-router-dom';
import AppContextProvider from './context/appContext';
import HomePage from './pages/HomePage';

const App: React.FC = () => {
  return (
    
      
        
      
    
  );
};

export default App;

Leave a Reply