名符其實的react下一代狀態管理器hox

前言

自從React16版本發佈Hooks以來,你們紛紛上車嚐鮮。毫無疑問,Hooks在必定程度上解決了組件間功能和邏輯複用的問題,在組件間的邏輯的封裝和複用確實真香,但Hooks在數據狀態的共享方法略有不足,雖然可使用useReducer實現數據狀態管理,但在必定程度上是對redux的思想的複用。咱們知道reduxFluxdva等這些React狀態管理的工具,實際上都是對actiondispatchreduceruseStoreProviderContext這些概念的排列組合,概念太多,學習入手成本較高,項目使用都差很少,會有產生許多的模版代碼。javascript

hox

既然如此是否有學習成本比較低,入手簡單的針對Hooks的狀態管理器呢?答案是有,其中來自來自螞蟻金服體驗技術部hox就是這樣一種工具。下面咱們從學習、上手、原理幾個方法聊聊這個被定爲爲下一代React狀態管理器,看看其是否符合其定位的目標。前端

學習

hox來自螞蟻金服體驗技術部,其背後的團隊在React各類實踐場景上都有很豐富的經驗,所以其後續的維護和迭代仍是很靠譜的。可能由於其只有一個API,所以其文檔也是十分簡單的,一眼就能看到頭了。這對於咱們前端的開發者而言就是很友好的,因爲變幻無窮的前端,各類輪子、各類技術層出不窮,前端的娃娃們表示學不動了。而這種只有一個API的工具,咱們表示仍是能夠學的動的。hox的詳細文檔能夠參看github上的readme支持中英文,連接以下:java

  1. 中文文檔github.com/umijs/hox/b…
  2. 英文文檔github.com/umijs/hox/b…

特性

hox做爲下一代的狀態管理器,其具備以下特性:react

  1. 只有一個 API,簡單高效,幾乎無需學習成本
  2. 使用 custom Hooks 來定義 model,完美擁抱 React Hooks
  3. 完美的 TypeScript 支持
  4. 支持多數據源,隨用隨取

上手

hox的上手使用體驗仍是很不錯的,由於十分簡單。talk is cheap,show me code。咱們直接上碼看看。git

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

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

export default createModel(useCounter);
複製代碼
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>
  );
}
複製代碼

使用hox就是這麼簡單,經過createModel包裝一下將custom hook變成share hook,就能夠在各個組件之間共享數據狀態,並實現邏輯封裝和複用。github

原理

createModel會建立一個Executor組件的實例,並在執行custom hookcustom hook的執行結果會被保存起來。最後,它會返回一個新的share hook便是model hook實現數據和邏輯的共享。源碼以下:typescript

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<T, P>, hookArg?: P) {
  // 實例化一個容器,經過發佈訂閱模式實現對狀態改變的推送 
  const container = new Container(hook);
  // 實例化 Executor 組件,當數據發生改變時,notify 全部訂閱者進行更新
  render(
    <Executor
      onUpdate={val => {
        container.data = val;
        container.notify();
      }}
      hook={() => hook(hookArg)}
    />
  );
  // useModel 這是 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 hook 代理 custom hook 返回的值 Object.defineProperty(useModel, "data", { get: function() { return container.data; } }); return useModel; } // 這是 hook 依賴項對比函數 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; } 複製代碼

其原理圖以下:redux

hox原理圖

總結

簡言之,hox大道至簡,只有一個API,但其既能知足邏輯的封裝和複用,又能知足狀態複用和管理,值得嘗試的狀態管理器。ide

相關文章
相關標籤/搜索