preface

Since the React16 release, you’ve been getting on the Hooks. There is no doubt that Hooks solve the problem of function and logic reuse between components to a certain extent. The encapsulation and reuse of logic between components are really nice. However, Hooks’ sharing method of data state is slightly insufficient. We know that redux, Flux, DVA and other React state management tools are actually the combination of action, Dispatch, Reducer, useStore, Provider, Context and so on. There are too many concepts, and the learning cost is high. Project usage is similar, there will be a lot of template code generated.

hox

In that case, is there a low-cost, simple state manager for Hooks that you can start with? The answer is yes, and hox from Ant Financial’s experience technology department is one such tool. Let’s take a look at how this is supposed to be the next React state manager, and see if it fits the purpose of its position.

learning

Hox comes from the Experience technology Department of Ant Financial, and the team behind it has rich experience in various practice scenarios of React, so its subsequent maintenance and iteration are quite reliable. Probably because it has only one API, the documentation is fairly simple, with the head visible at a glance. This is very friendly to our front end developers, because because of the ever-changing front end, all kinds of wheels, all kinds of technology, the dolls on the front end are not able to learn. And with a tool that has only one API, we’re showing that you can learn it. Hox’s detailed documentation can be found on github readME support in Both English and Chinese, with links below:

  1. Chinese documents: github.com/umijs/hox/b…
  2. English documents: github.com/umijs/hox/b…

features

As the next generation state manager, HOX has the following features:

  1. Just one API, simple and efficient, with almost no learning cost
  2. Use Custom Hooks to define models, which perfectly embrace React Hooks
  3. Perfect TypeScript support
  4. Support for multiple data sources, on-demand

Get started

The hox experience is great because it’s so simple. Talk is cheap, show me code. Let’s go straight to the code.

import { useState } from "react";
import { createModel } from "hox";

function useCounter() {
  const [count, setCount] = useState(0);
  const decrement = (a)= > setCount(count - 1);
  const increment = (a)= > setCount(count + 1);
  return {
    count,
    decrement,
    increment
  };
}

export default createModel(useCounter);
Copy the code
import useCounterModel from ".. /models/counter";

function App(props) {
  const { count, increment, decrement } = useCounterModel();
  return (
    <div>
      <p>{count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
}
Copy the code

Using HOx is as simple as that, with createModel wrapping custom hooks into Share hooks, sharing data state between components, and enabling logical encapsulation and reuse.

The principle of

CreateModel creates an Executor component instance and executes the Custom hook. The results of the custom hook execution are saved. Finally, it returns a new Share hook, or Model Hook, to share the data and logic. The source code is as follows:

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 function createModel<T.P> (hook: ModelHook
       
        , hookArg? : P
       ,>) {
  // Instantiate a container to push state changes using a publisit-subscribe pattern
  const container = new Container(hook);
  // Instantiate the Executor component and notify all subscribers when data changes
  render(
    <Executor
      onUpdate={val= > {
        container.data = val;
        container.notify();
      }}
      hook={(a)= > hook(hookArg)}
    />
  );
  // useModel This is the share hook
  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]);
    return state! ; }; //share hookThe agentcustom hookThe value returnedObject.defineProperty(useModel, "data", {
    get: function() {
      returncontainer.data; }});
  return useModel; } / / it ishookDependency contrast functionfunction 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

The schematic diagram is as follows:

conclusion

In short, hox avenue to simple, only one API, but it can meet both logic packaging and reuse, and can meet the state reuse and management, worth trying the state manager.