preface

Previously React Hooks: Redux has nothing in common with hooks, although many of the hooks design comes from redux. Redux has nothing in common with hooks. As for Mobx, there are hooks based on hooks like useLocalStore, useObserve, etc., but I don’t feel that hooks are very handy either. My personal view is that redux and Mobx are more focused on centralized management. Hooks emphasize state sharing. Recently, I found two interesting status management tools, one is Recoil from The official lab of Fackbook (not React official) and Hox from Ant Financial. After contacting both of them, I found that recoil has a lot of concepts and apis to understand, which are not that delicious. Here are a few highlights of hox, which I find both simpler and better suited to hooks

What is the

Hox is ant Financial’s next generation React state manager.

I think there are two reasons for this confidence. One is that there is only one API — createModel, which is as simple as documentation. The second point is that Hox perfectly embraces the React hooks, which are backed by the React authorities, so unilaterally announcing the next generation is still acceptable.

why

Why does Hox prefer state management for hooks of boxes? Combine source code to say my personal view below!

In terms of usage, hox basically only has to deal with one API, createModel, which deserves a thumbs up. (There are apis such as withModel(used in the class component), of course, but these feel like two-for-one deals.) For its design, HOX makes perfect use of the hooks’ own powerful state management, but hooks are for single components, so hox makes clever use of the React Reconciler, using custom renderers to collect the states of scattered components in model units. Sort of like pulling the hooks definition out, or creating an additional component tree that implements shared hooks via custom hooks and custom renderers, and notifies individual components of status updates via the Container.

Direct source code (divided into three pieces of parsing) :

import { ModelHook, UseModel } from "./types";
import { Container } from "./container";
import { Executor } from "./executor";
import React, { useEffect, useRef, useState } from "react";
import { render } from "./renderer";

export functioncreateModel<T, P>(hook: ModelHook<T, P>, hookArg? : P) {/** * ES6 uses the Set structure to store observers, and then exposes the notify method to notify all observers of updates. Subscriber function */ const container = new container (hook); /** * The React Reconciler + Executor component customizable generates a renderer that notifys all observers of status updates through observer mode, which is to execute the subscriber function stored in the Set structure. The Executor component mainly performs two functions. One is the hook passed in by createModel. <Executor onUpdate={val => {container. Data = val; container.notify(); }} hook={() => hook(hookArg)} /> ); // Use useState to hook the state of the Container to React's own state management. Through exposure depsFn function to control whether to update the status / / (2) through the useEffect registration/moving / / (3) in addition to the observer through defineProperty hijacked the custom data attributes of hooks, to expose the data of the container Const useModel: useModel <T> = depsFn => {const [state,setState] = useState<T | undefined>(() =>
      container ? (container.data as T) : undefined
    );
    const depsFnRef = useRef(depsFn);
    depsFnRef.current = depsFn;
    const depsRef = useRef<unknown[]>([]);
    useEffect(() => {
      if(! container)return;
      function subscriber(val: T) {
        if(! depsFnRef.current) {setState(val);
        } else {
          const oldDeps = depsRef.current;
          const newDeps = depsFnRef.current(val);
          if (compare(oldDeps, newDeps)) {
            setState(val);
          }
          depsRef.current = newDeps;
        }
      }
      container.subscribers.add(subscriber);
      return () => {
        container.subscribers.delete(subscriber);
      };
    }, [container]);
    returnstate! ; }; Object.defineProperty(useModel,"data", {
    get: function() {
      returncontainer.data; }});return useModel;
}

function compare(oldDeps: unknown[], newDeps: unknown[]) {
  if(oldDeps.length ! == newDeps.length) {return true;
  }
  for (const index in newDeps) {
    if(oldDeps[index] ! == newDeps[index]) {return true; }}return false;
}
Copy the code

How to use

Hox is relatively easy to use, you can refer to the documentation directly

Show me the code! Here is todoList based on redux and HOX implementations

Redux: Based on the reudx official example + React Profiler

Hox: based on hox + React Profiler

Write in the last

  1. With the hoX mental model, the model should be divided into units with specific functions

The main cost of Hooks, as I said earlier, is not the learning of apis, but the transformation of mental models. This also applies to HOX. In Redux and MBox we are more concerned with stroe state changes, but in HOX we are more concerned with each model, specifically the custom hooks that are wrapped by createModel, which are more concerned with specific function logic. Like todoList above, we are writing hooks that should implement todoList which adds todo, can change todo state, and filters.

  1. Performance comparison and optimization

The React Profiler and the React Profiler are both used as simple performance comparisons. Hox provides depsFn to optimize performance. The hox version of TodoList renders three components (addTodo, TodoList, And FilterFooter) for the first time. Redux renders a component (VisibleTodoList); The second addTodo operation, the HOX version also renders two components (addTodo, TodoList). I have been thinking about this point for a long time and have not thought of a good optimization method. Personally, I think it is the design of HOX itself that causes the problem. (It may also be that there is a problem with the writing method, which needs further exploration. However, I think hoX can beat Redux in terms of writing and reusability as long as we divide up the model and use depsFn.

  1. Pay attention to issue

During the process from learning to read the source code to writing this article, I have been paying attention to the issue of HOX, feeling a little tepid and feeling that most people are in a wait-and-see state. Now the latest issue is about HOX V2, which is quite interesting. Due to the many drawbacks of V1 version, V2 intends to cooperate with context. This also means that the user needs to write the provider manually, but the API is relatively simple compared to other context-based libraries. Therefore, considering the situation of Issuse and HOx, I feel that small projects (such as activity pages, etc.) should be added to hoX, while large projects are not necessary. I should keep an eye on them and hope that HOX can continue to get hooked. Even if HOX doesn’t make it to the forefront of state management, its design ideas and source code are worth reading and learning!