react atom_使用Atom抽象开发React全球状态库

章稳
2023-12-01

react atom

介绍 (Introduction)

I have been developing various global state libraries for React. For example:

我一直在为React开发各种全局状态库。 例如:

My main motivation is to eliminate selector functions that are only required for render optimization. Render optimization here means it avoids extra re-renders. An extra re-render is a re-render process that produces the same view result as before.

我的主要动机是消除仅渲染优化所需的选择器功能。 这里的渲染优化意味着避免了额外的重新渲染。 额外的重新渲染是一个重新渲染过程,它产生与以前相同的视图结果。

Since Recoil is announced, I’m very interested in atom abstraction because it eliminates selector functions for render optimization and the API seems pretty intuitive.

自宣布Recoil以来,我对原子抽象非常感兴趣,因为它消除了用于渲染优化的选择器功能,并且API看起来非常直观。

I couldn’t help stopping creating something by myself. This post introduces my challenges up to now with some notes.

我禁不住自己一个人创作。 这篇文章通过一些注释来介绍我到目前为止的挑战。

反冲 (Recoildux)

My first challenge was to use a Redux store as an atom. Redux itself is very lightweight. Although the ecosystem assumes only one Redux store exists in an app, we could technically create as many stores as we want.

我的第一个挑战是使用Redux存储作为原子。 Redux本身非常轻巧。 尽管生态系统假定一个应用程序中仅存在一个Redux商店,但从技术上讲,我们可以根据需要创建任意数量的商店。

I have already developed a react redux binding for Concurrent Mode. It uses the upcoming useMutableSource hook, and most notably it doesn’t depend on React Context.

我已经为并发模式开发了一个React Redux绑定。 它使用即将到来的useMutableSource挂钩,最值得注意的是,它不依赖于React Context。

reactive-react-redux is the repository and especially #48 has the code as of writing.

react-react-redux是存储库,尤其是#48具有编写时的代码。

Based on it, the implementation is pretty straightforward. Only the challenge is how to create a new atom based on existing atoms. I wanted to something similar to combineReducers, and created combineAtoms. Unfortunately, it didn’t go well: a) the API is not very flexible and b) the implementation is too hacky.

基于此,实现非常简单。 唯一的挑战是如何在现有原子的基础上创建一个新原子。 我想要一个类似于combineReducers东西,并创建了combineAtoms 。 不幸的是,它进行得并不顺利:a)API不太灵活,b)实现过于hacky。

On the other hand, Recoil-like selector is implemented more cleanly and it’s flexible.

另一方面,类似于Recoil的selector实现起来更干净,并且更灵活。

Here’s the repository.

这是存储库。

Unfortunately, the current implementation of atom has builtin reducer, and we can’t use custom reducer. Most of Redux ecosystem is not very usable for this, so it doesn’t get much benefit of using Redux. (Except that I could build it fairly quickly based on reactive-react-redux v5-alpha.)

不幸的是,atom的当前实现具有内置的reducer,我们不能使用自定义的reducer。 大多数Redux生态系统对此都不太有用,因此使用Redux并不会带来太多好处。 (除了我可以基于reactive-react-redux v5-alpha快速构建它。)

React钩子全球状态 (react-hooks-global-state)

I have been developing this for a long time with various assumptions.

我已经使用各种假设开发了很长一段时间。

As of writing, v1 is pretty stable based on subscription model. v2-alpha is also implemented with useMutableSource and should be Concurrent Mode compatible.

在撰写本文时,基于订阅模型,v1非常稳定。 v2-alpha也可以通过useMutableSource实现,并且应该与并发模式兼容。

The current API is mainly for a single store or a small set of them. Based on my first challenge with Recoildux, I was pretty sure atom abstraction is possible and easy without derived atoms. Still, there are a few benefits. a) It allows the pattern of small and many stores. b) It enables code splitting.

当前的API主要用于单个商店或一小部分商店。 基于我对Recoildux的第一个挑战,我很确定没有派生原子,原子抽象是可能且容易的。 仍然有一些好处。 a)它允许小型商店和许多商店的模式。 b)启用代码拆分。

v1 compatible APIs are simple wrappers around atom abstraction. So, even without derived atoms (= Recoil’s selector), atom abstraction makes a certain sense.

兼容v1的API是原子抽象的简单包装。 因此,即使没有派生的原子(= Recoil的selector ),原子抽象还是有一定意义的。

Here’s the code as of writing.

这是编写时的代码。

https://github.com/dai-shi/react-hooks-global-state/pull/38

https://github.com/dai-shi/react-hooks-global-state/pull/38

I’d say the implementation has nothing special. It’s only about the use of the terminology “atom” which means small store in this case.

我会说实现没有什么特别的。 这仅与术语“原子”的使用有关,在这种情况下,这意味着较小的存储量。

使用原子 (use-atom)

The previous two libraries are for so called external stores. It means stores are created outside of React. That is totally fine. However, in Concurrent Mode it’s recommended to use React state for state branching. For more information about Concurrent Mode, check out the React doc.

前两个库用于所谓的外部存储。 这意味着商店是在React之外创建的。 很好 但是,在并发模式下,建议使用React状态进行状态分支。 有关并发模式的更多信息,请查看React doc

I have been developing react-tracked and know how difficult to create global state only with React state.

我一直在进行React跟踪开发,并且知道仅使用React状态创建全局状态有多困难。

Luckily, there is a library to ease it, which is use-context-selector. Based on this, it would only require small effort to create a new library with atom abstraction.

幸运的是,有一个可以简化它的库,它是use-context-selector 。 基于此,只需很少的精力即可创建一个具有原子抽象的新库。

Here’s the repository.

这是存储库。

Contradictory to my expectation, it was extremely hard to implement. There are many reasons but some notable ones are:

与我的预期相反,这很难实施。 原因很多,但值得注意的是:

  1. API seems simple and intuitive, but that doesn’t mean the implementation is simple. For example, it’s hard to know if an updating action is sync or async. We’d want to show loading indicator only if the action is async.

    API看起来简单直观,但这并不意味着实现简单。 例如,很难知道更新操作是同步还是异步。 我们只想在操作异步的情况下显示加载指示器。
  2. Handling atom dependencies is not trivial. We need to create a dependency graph, but we don’t know it in advance. We can only know it at runtime. Furthermore, there’s no way to remove dependencies if they are no longer dependent.

    处理原子依赖性并非易事。 我们需要创建一个依赖图,但是我们事先并不知道。 我们只能在运行时知道它。 此外,如果不再依赖,则无法删除依赖。
  3. It’s almost impossible to suspend correctly for React Suspense. It’s already noted above, but we can’t know what is async and what is dependent.

    正确暂停React Suspense几乎是不可能的。 上面已经提到了,但是我们不知道什么是异步的以及什么是依赖的。

The current version of use-atom tries to do its best. There’s various edge cases that it doesn’t work as expected. I don’t think the implementation is polished, and there might be better way we would find in the future.

当前版本的use-atom会尽力而为。 在各种情况下,它无法按预期工作。 我认为实现不是完美的,将来我们可能会找到更好的方法。

Note that use-atom has a compatibility layer with Recoil. But, it doesn’t fully replicate the API and there are some limitations and inconsistencies. Nevertheless, it’s compatible for simple cases, and we can compare the behavior between use-atom and Recoil.

请注意,use-atom具有与Recoil的兼容层。 但是,它不能完全复制API,并且存在一些限制和不一致之处。 但是,它与简单情况兼容,我们可以比较use-atom和Recoil之间的行为。

结束语 (Closing notes)

It was nice experience trying these challenges. One of big findings for me is simple API for users is not always easy to implement. This may sounds obvious, but it’s something I learnt from this. If the implementation is hard, it’s likely to have more bugs. I hope to find a variant of atom abstraction that is intuitive to users and not complicated to implement.

尝试这些挑战是很不错的经验。 对我来说,一大发现是,针对用户的简单API并非总是易于实现。 这听起来似乎很明显,但这是我从中学到的。 如果实施困难,则可能会有更多错误。 我希望找到一种原子抽象的变体,它对用户来说是直观的,并且实现起来并不复杂。

Originally published at https://blog.axlight.com on August 12, 2020.

最初于 2020年8月12日 发布在 https://blog.axlight.com 上。

翻译自: https://medium.com/weekly-webtips/developing-react-global-state-library-with-atom-abstraction-713903380143

react atom

 类似资料: