把 umi 的 useModel 抽离到其他项目中使用

1,170 阅读2分钟

我正在参加「掘金·启航计划」

使用原因

由于管理端是采用umiantd来开发,而其中的全局状态是采用umiuseModel来进行管理的。使用感受就是用起来挺舒服的。

在小程序的开发中也需要用到全局的状态管理,一开始为了赶进度,没多想以为useModel只能用在umi,然后就采用单例模式来进行维护全局的状态了,但是采用这种方法最大的弊端就是每次数据更改,都要手动render一下,然后页面与页面之间数据变化了,又要处理什么时候该render

现在有点时间研究,发现umiuseModel原来已经给我们打包好了,只需稍稍处理就能在其他项目中使用了。

开始抽离

umi项目中的路径为:src/.umi/plugin-model,把plugin-model整个文件夹复制到其他项目中

打开useModel.tsx,进入isEqual里面然后把整个文件也粘出来。

打开Provider.tsx,将里面的initialState也粘出来。

// 里面就这样一行代码(想怎么处理都行)
export default () => ({ loading: false, refresh: () => {} })

在其他项目中使用

  1. 因为useModel主要是采用了useContext来进一步封装出来的钩子,所以想要全局使用,就要在整个项目最外层包裹一层。我这里是taro小程序中使用,所以就包裹在这里了,当然也可以只包裹需要使用的那些父组件(这样就是那些父组件和里面的子组件才能使用了)。
  1. model文件夹中(在其他文件中也行),简单写一个model
import { useState, useCallback } from 'react';

type UserInfo = {
  avatar?: string;
  name?: string;
};
export default function useAuthModel() {
  const [userInfo, setUserInfo] = useState<UserInfo>({name: 'lhh'});
  const setUser = useCallback((userInfo: UserInfo) => {
    setUserInfo(userInfo);
  }, []);

  return {
    userInfo,
    setUser,
  };
}
  1. 引入自己的model,打开Provider.tsx,手动引入
  1. 简单使用
import NavBar from '@/components/navBar';
import { View, Button } from '@tarojs/components'
import Taro from '@tarojs/taro';
import './index.less';
import { useModel } from "@/hooks/useModel";

export default () => {
  // 这里的 user-info 就是第三步引入的时候自己写的 key 值
  const { userInfo } = useModel('user-info')
  
  return (
    <View className='page-test-useModel'>
      <NavBar title={'test-页面一'} />
      <View className="name">这里是父组件:{userInfo?.name}</View>
      <Children></Children>
      <Button onClick={() => Taro.navigateTo({url: '/pages/aatest-useModel2/index'})}>去下个页面</Button>
    </View>
  )
}

const Children = () => {
  const {userInfo, setUser} = useModel('user-info')
  return (
    <View className='com-useModel-c-t'>
      <View className="title">--子组件--</View>
      子组件姓名:{userInfo?.name}
      <Button className="btn" onClick={() => {
        setUser({...userInfo, name: 'lhh改名了' + Date.now()})
      }}>子组件改名</Button>
    </View>
  )
}