自從React16
版本發佈Hooks
以來,你們紛紛上車嚐鮮。毫無疑問,Hooks
在必定程度上解決了組件間功能和邏輯複用的問題,在組件間的邏輯的封裝和複用確實真香,但Hooks
在數據狀態的共享方法略有不足,雖然可使用useReducer
實現數據狀態管理,但在必定程度上是對redux
的思想的複用。咱們知道redux
、Flux
、dva
等這些React
狀態管理的工具,實際上都是對action
、dispatch
、reducer
、useStore
、Provider
、Context
這些概念的排列組合,概念太多,學習入手成本較高,項目使用都差很少,會有產生許多的模版代碼。javascript
既然如此是否有學習成本比較低,入手簡單的針對Hooks
的狀態管理器呢?答案是有,其中來自來自螞蟻金服體驗技術部hox就是這樣一種工具。下面咱們從學習、上手、原理幾個方法聊聊這個被定爲爲下一代React
狀態管理器,看看其是否符合其定位的目標。前端
hox
來自螞蟻金服體驗技術部,其背後的團隊在React
各類實踐場景上都有很豐富的經驗,所以其後續的維護和迭代仍是很靠譜的。可能由於其只有一個API
,所以其文檔也是十分簡單的,一眼就能看到頭了。這對於咱們前端的開發者而言就是很友好的,因爲變幻無窮的前端,各類輪子、各類技術層出不窮,前端的娃娃們表示學不動了。而這種只有一個API
的工具,咱們表示仍是能夠學的動的。hox
的詳細文檔能夠參看github
上的readme
支持中英文,連接以下:java
hox
做爲下一代的狀態管理器,其具備以下特性:react
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 hook
, custom 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
大道至簡,只有一個API
,但其既能知足邏輯的封裝和複用,又能知足狀態複用和管理,值得嘗試的狀態管理器。ide