一个懒人封装的redux库

当一个人写了多年的代码之后,就会开始变得懒惰。倒不是说懒得工作赚钱了,而是懒得写重复的代码了。笔者在一家公司常年使用react + redux + antd 三件套,不得不说写的好烦,状态管理一顿操作后发现还被困在模板代码里无法自拔。

写一个reducer到底有多费劲?

typescript 复制代码
export const MY_ACTION_TYPE = 'my_type'

export const myAction = (payload) => {
  return {
    type: MY_ACTION_TYPE,
    payload,
  }
}

export const myReducer = (state = {}, action) => {
  switch (action.type) {
    case MY_ACTION_TYPE:
      return { ...state, ...action.payload };
      break;
    default:
      return state;
  }
}

export const reducers = combineReducers({
  myReducer,
})

难以忘怀的吐槽点:

  • 重复地写ACTION_TYPE,它是连接action和reducer的暗号
  • 重复的action模板
  • 重复的reducer模板,千篇一律的switch/case以及烦人的扩展操作符
  • 总是忘记在store实例导入reducer,导致数据不存在
  • reducer的action.payload会根据action.type变化,难以融合TS类型

这能忍?作为懒人的我肯定是忍不了的。有这时间写重复模板,我为啥不拿去划水吹逼增进感情?

找找其它状体库吧:

  • dva :为啥那么多yield语法?怎么跟TS结合?好久不更新了?还绑定了路由?有事先走一步
  • rematch:整体不错,但对TS的支持稍微弱了一些,至少还没让我很满意
  • recoil:提供的api有点多,看得头皮发麻。而且不支持class组件
  • jotai :就两个api,可以1分钟上手,类似setState。可惜就是太纯粹了,不支持异步操作,毕竟大部分场景我们都需要请求接口并存入数据。
  • mobx:一个Proxy走天下,随时随地都可以改状态,项目大了不可控。另外装饰器现在还是残次品,个人不喜欢。(但是mobx作者写的immer真香)
  • redux-toolkit:redux官方出品,虽然简洁不少,但还是没有跳出redux的禁锢

其实也有不少国内外开发者开源了自己的状态库。有些很优秀,但可能宣传不到位。有些维护一段时间就弃坑(公司KPI,失业转行,能力受限)了,留下一地鸡毛。有些纯粹是50行代码玩具,但是拥护者极多。

苦不堪言。既要好用,又要好学,还要完美支持Typescript,同时这个开源项目不能弃坑?身为一个拥有10年经验的程序员,当然是自己造轮子啦。

谈谈我的乌托邦幻想:

  • 它是一个模块,一份状态就在一个文件里,包括相关的变更操作
  • 不想再多写任何一行重复的代码
  • 打破禁锢。我们的项目里其实一直只有一个store不是吗?
  • 能提供异步函数,还要能知道函数的执行状态
  • 必须完美支持Typescript!!
  • 诱人的计算属性
  • 不要复杂的概念,能让开发者不看文档都能猜到个大概

结合各家优点,一个新的状态库诞生:foca (foca.js.org)

typescript 复制代码
import { dfineModel } from 'foca';
import axios from 'axios';

const initialState: { name: string; age: number; posts: object[] }  = { 
  name: 'foo', 
  age: 30, 
  posts: [],
}

export const profileModel = defineModel('profile', {
  initialState,
  reducers: {
    udpateAge(state, age: number) {
      state.age = age;
    },
  },
  methods: {
    async getPosts() {
      const result = await axios.get<object[]>('/api/posts')
      this.setState({ posts: result });
    },
    async getProfile() {
      const result = await axios.get<{ age: number }>('/api/profile');
      this.updateAge(result.age);
    },
  },
  computed: {
    firstPost() {
      return this.state.posts[0];
    },
    postCount() {
      return this.state.posts.length;
    },
  },
});

似乎我想要的都在里面了?模块化、没有模板、异步支持、完美的TS提示(没有写类型的地方都能自动提示)、计算属性、概念简单(看名字就知道是啥)。

不,还远远不够。前面提到了,大多数的项目里,其实只有需要一个store,所以foca也这么认为,它变成了单例模式。有了这个前提,事情就好办多了,我们不需要dispatch不需要注册,导出即可使用,别提多方(懒)便(惰)了。

typescript 复制代码
import { type FC,useEffect } from 'react';
import { useModel, useComputed, useLoading } from 'foca';
import { profileModel } from './profile.model';

const App: FC = () => {
  const username = useModel(profileModel, (state) => state.name);
  const postCount = useComputed(profileModel.postCount);
  const loading = useLoading(profileModel.getProfile, profileModel.getPosts);
  
  useEffect(() => {
   profileModel.getProfile();
   profileModel.getPosts();
  }, []);
  
  if (loading) return <p>Loading...</p>;
  return <p>Hello { username }, you have { postCount } posts.</p>
}

export default App;

有没有耳目一新的感觉呢?视图逻辑内不再指定TS的类型,因为都是自动推导出来了。业务逻辑也是清晰明了,恰到好处,整体写完就一个字: !它基于redux,但开发者不再需要了解redux,用最简单粗暴直观的方式即可完成功能。

总结:

程序员因为懒而封装了各种轮子提升开发效率,轮子的愿景就是让使用者感觉到幸福,使用时温和不聒噪,使用后回味无穷,谈论时赞美有加。


foca,流畅的状态管理库 foca.js.org

相关推荐
且陶陶º2 个月前
【案例】使用React+redux实现一个Todomvc
javascript·react.js·redux
Orzak3 个月前
[译]全栈Redux实战
redux
摇光935 个月前
React + 项目(从基础到实战) -- 第十期
前端·javascript·react.js·redux
石小石Orz5 个月前
不要滥用Pinia和Redux了!多组件之间交互可以手写一个调度器!
前端·vuex·redux
豆浆不好喝6 个月前
深入浅出之redux-thunk
react.js·redux
程序员小杨v16 个月前
Zustand不仅使用起来简单,源码更简单
前端·react.js·redux
大前端秘籍6 个月前
实战指南:使用Zustand与Immer简化状态管理
前端·react.js·redux
前端小超人rui6 个月前
【 Redux 】 Redux中间件的理解?常用的中间件有哪些?实现原理?
前端·react·js·redux
JudithHuang6 个月前
安装和使用 Redux DevTools 插件
react.js·redux
JudithHuang6 个月前
实现React组件之间的数据共享:使用React Redux
react.js·redux