阅读 259

在taro中使用useContext实现全局数据注入

相信全局数据同步是每个前端开发都会遇到的问题,在实际开发过程中,比较常见的方式有redux, mobx, vuex等

然而,在使用了react hooks后,有一种更加简便优雅的方式,那就是使用useContext这个钩子

在普通的react项目中,我们可以很自然地使用useContext,但是,最近我们项目组打算使用taro重构项目,于是花了点功夫进行技术调研,踩了一些坑,所以还是写点总结,希望能给小伙伴们提供点帮助。

useContext的具体使用方式可以查看官方文档

在taro 2.2.6版本中使用

在实际开发项目中,useContext的使用方式比较不太方便,于是借鉴了unstated-next这个库的源码,在本地创建了一个useContainer的hook,替换原来的React.createContext为Taro.createContext,然后就可以愉快地使用啦

步骤1: 创建useContainer.ts

import Taro from "@tarojs/taro";

const EMPTY: unique symbol = Symbol();

export interface ContainerProviderProps<State = void> {
  initialState?: State;
  children: any;
}

export interface Container<Value, State = void> {
  Provider: any;
  useContainer: () => Value;
}

export function createContainer<Value, State = void>(
  useHook: (initialState?: State) => Value
): Container<Value, State> {
  let Context = Taro.createContext<Value | typeof EMPTY>(EMPTY);

  function Provider(props: ContainerProviderProps<State>) {
    let value = useHook(props.initialState);
    return <Context.Provider value={value}>{props.children}</Context.Provider>;
  }

  function useContainer(): Value {
    let value = Taro.useContext(Context);
    if (value === EMPTY) {
      throw new Error("Component must be wrapped with <Container.Provider>");
    }
    return value;
  }

  return { Provider, useContainer };
}

export function useContainer<Value, State = void>(
  container: Container<Value, State>
): Value {
  return container.useContainer();
}
复制代码

步骤2: 写一些需要在全局使用的数据

import { createContainer } from "./useContainer";
import { useState } from "@tarojs/taro";

export default createContainer(() => {
  const [count, setCount] = useState(0);
  // 这里可以做一些数据的获取操作,例如发送请求之类的

  return {
    count,
    setCount,
  };
})
复制代码

步骤3: 在入口文件app.tsx中,注入全局数据

import Container from "./hooks/index";

# 省略部分代码

Taro.render(
  <Container.Provider>
    <App />
  </Container.Provider>,
  document.getElementById("app")
);

复制代码

这里遇到的一个小坑就是,我们不能在App类里面写注入代码,因为那个render其实是没起实际作用的。

写到这里,似乎就大功告成了,写一下测试数据,运行npm run dev:h5,可以在组件和嵌套页面中正常显示我们注入的全局数据

然而,运行npm run dev:weapp,似乎在小程序中并不支持......

正巧在调研的时候Taro 3.0发布了,于是更新了一波taro,试试有没有支持

在taro 3.0.0-rc.6版本中使用

  • 通过taro update self命令,我们将taro更新到最新的版本
  • taro init my-taro-demo初始化一个项目
  • taro 3.0中内置了React,因此我们可以直接引入unstated-next这个包,不需要创建本地的useContainer
  • 重复步骤2
  • 修改初始化项目中的app.ts为app.tsx(划重点),修改app.tsx
import Container from "./hooks/container";

# 省略部分代码

 render() {
    return <Container.Provider>{this.props.children}</Container.Provider>;
  }
复制代码

最后,分别运行npm run dev: h5 和 npm run dev:weapp,都能完美显示~