关于javascript:20-行简单实现一个-unstatednext-🎅

前言 📝

👉 unstated-next 基于 React 心智模型(hook+context)而设计的状态治理。 👈

在 react hook 呈现之前,有基于繁多数据源,应用纯函数批改状态的 redux & react-redux 也有基于 Object.defineProperty 和 Proxy 来进行数据拦挡拜访的 mobx ,但随同着 react 16.8 的呈现,咱们能够基于自带的 hook 去实现状态治理也就是 unstated-next


官网 Demo 🥔

...
import { createContainer } from "unstated-next";

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

//应用 createContainer 将 useCounter革新成提供状态和办法的组件
let Counter = createContainer(useCounter);

function CounterDisplay() {
//从被解决过的 useCounter 中拿到状态和办法
  let counter = Counter.useContainer();
  return (
    <div>
      <button onClick={counter.decrement}>-</button>
      <span>{counter.count}</span>
      <button onClick={counter.increment}>+</button>
    </div>
  );
}

function App() {
  return (
    <Counter.Provider>
      <CounterDisplay />
      {/* 通过initialState属性注入初始值 */}
      <Counter.Provider initialState={2}>
            <CounterDisplay />
      </Counter.Provider>
    </Counter.Provider>
  );
}

render(<App />, document.getElementById("root"));

unstated-next 做了什么?

  1. 提供 createContainer 将自定义 Hooks 封装为一个能够提供状态和办法的 数据对象
  2. 利用 useContext 结构了 Provider 注入组件获取获取 Store 这两个办法

实现一个 unstated-next 🚲

import { createContext, createElement, useContext } from "react";
export default useHook => {
  const Context = createContext();
  const Provider = ({ init, children }) => {
    return createElement(Context.Provider, { value: useHook(init) }, children);
  };
  const useContainer = () => useContext(Context);
  return { Provider, useContainer };
};
  • 通过函数返回一个蕴含ProvideruseContainer的对象
  • Provider 承受 init 初始值,去执行 数据对象 组件,通过 createElement 发明一个 Context.Provider 传值组件,并将 数据对象 组件返回的办法和状态保留到value,子节点不变,返回:
<xxx.Provider value={办法,状态...}>{children}</xxx.Provider>
  • 通过useContainer拿到 以后 Context.Provider 中的 value 状态和办法 并返回

如何解决 Provider hell 🏁

在 unstated-next 中每一个被解决为 数据对象 的组件如果想要被共享,须要在最外层逐级包裹

<Container1.Provider>
  <Container2.Provider>
    <Container3.Provider>MyApp</Container3.Provider>
  </Container2.Provider>
</Container1.Provider>

咱们能够通过 相似 compose 函数进行解决,将所有 数据对象 组件通过 reduce 逐级叠加返回一个相似洋葱的 Provider,调用的时候只须要应用Provider包裹住业务组件

export const composeProvider = (...commonFun) => ({ children }) => {
  return commonFun.reduceRight((child, { init, Provider }) => {
    return <Provider init={init}>{child}</Provider>;
  }, children);
};

//进行调用
const Provider = reduceProvider({ ...xxxState1, init: 100 }, xxxState2);
export default () => (
  <Provider>
    <ExamplePage1 />
    <ExamplePage2 />
    <ExamplePage3 />
  </Provider>
);

查看残缺代码

功败垂成!

总结 💢

总结

其实 unstated-next 实现很简略,艰深来讲就是一个闭包,应用于简略的业务场景,且写法过于灵便,一旦遇到 class 组件的状况,就又要回到旧的写法,所以只能说有利有弊

至此,谢谢各位在百忙之中点开这篇文章,心愿对你们能有所帮忙,置信你对 unstated-next 有了大略的认实,如有问题欢送各位大佬斧正。

欢送增加我的微信独特探讨前端技术问题(备注:qian)

  • 👋:跳转 github

参考文献

  • 🍑:unstated-next
  • 🍑:React hooks,组合与形象,状态治理
  • 🍑:精读《unstated 与 unstated-next 源码》
  • 🍑:React 轻量状态治理库 unstated-next 应用教程

求个 star,谢谢大家了

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理