Original link: https://blog.rxliuli.com/p/1fcd1517c14c4e68b764d7e6df071805/
foreword
In react hooks, useEffect is the most commonly used hooks function, but its api experience of manually managing dependency status has been criticized for a long time. There are countless articles on how to use useEffect correctly in the community, but it still can’t stop more newcomers. The fact of using this api correctly is also dubbed the react newcomer wall. Moreover, among popular web frameworks, only react needs to manually manage hooks dependencies. Other frameworks such as vue, svelte and solidjs do not require manual dependency management. The recent hot discussion about signals in the react community also reflects that more people have realized the badness of this kind of dx, and preact even officially supports signals .
Why did signals become popular all of a sudden?
Well, my guess is the adoption of solidjs. Although vue and svelte do not need to manually manage dependencies, they are very different from react in the way they are written. They all have their own template syntax. Vue even requires additional plug-ins to use jsx, and the experience is not very good, so it is better Many see them as differences between different frameworks – not which hooks api is better. While solidjs fully adopts the jsx syntax and community-related tool chain, but the state management is more friendly to developers. Using useEffect/useMemo/useCallabck no longer needs to manually manage dependencies, but automatically handles them in an efficient manner.
The following video best expresses my views
The one-pass operation of react is as fierce as a tiger, and as a result, a signal solves all problems more elegantly.
The operations shown are
- virtual dom
- immutable data
- hooks
- dependent array
- Compiler optimizations and automatic caching
for example
Dependency transmission has dependencies, and the functions useEffect/useMemo/useCallback
all depend on deps array parameters. And they can also depend on each other. For example, the value of useMemo can be used as a dependency by useCallback. In short, if you use these common react hooks, you must manually manage the dependency graph between them. If not managed correctly, very subtle bugs can arise. React provides eslint rules to check, but on the one hand, not all projects use eslint. On the other hand, this eslint rule is usually too strict and must be manually closed in some cases. For example, when using useEffect, you want to trigger according to the change of a value Side effect, but at the same time needs to read the latest b value, and eslint rules blow up in this respect. On the other hand, the status of react cannot be read immediately after modification. This is not caused by react hooks, but a problem that has always existed in react.
Status update and read
The traditional mental model, you read the latest value immediately after modifying the variable.
1 |
|
The mental model of react uses await new Promise(resolve => setTimeout(0, resolve))
to wait for the next cycle to read the latest value.
1 |
|
The main problem with this approach is that it is verbose, not intuitive and not particularly reliable.
Or use a temporary variable to hold the new value and use the new value later.
1 |
|
This method may be used more in practice, mainly because additional variables need to be created
Or use immer, you can use produce to wrap a layer, so that the latest value can be read after modification in the callback.
1 |
|
But this function does not work well with asynchronous functions. For example, the following code is impossible, because when the callback accepted by produce returns a Promise, the result of the produce function will also be a Promise, which is not available for the set function of react. Of course you can add await, but you need to merge and split when there are multiple states. These boilerplate codes are very annoying.
1 |
|
code using mobx
1 |
|
The advantage of this model is that you can directly modify the state without using the set function, and you can directly read the latest value without using await to wait for the next cycle. Basically, it’s similar to vue’s reactive hooks, generating a mutable object that can then be modified and read, even deep. In a sense, vue3 hooks is indeed a simplification of react + mobx, but compared to jsx, templates make many people unaccustomed (dislike).
dependency hell
For example, the following code is very common in react
1 |
|
Using mobx can be rewritten as
1 |
|
However, in general, mobx may only manage state, and related functional functions are placed at the top level of components.
1 |
|
The same is true for useMemo, which can be replaced by mobx’s computed. Similarly, it is automatically optimized.
1 |
|
Encapsulate some tool hooks
Sure, mobx might have some boilerplate code, but that can be solved with some encapsulation, looks like vue hooks xd.
1 |
|
limitation
While mobx is good, it has some limitations
- Requires some boilerplate code observer/useLocalStore
- Subcomponents can modify the state passed in
- ToJS is needed to convert the proxy proxy object into a normal js object during structured cloning
- There is no direct explicit declaration of dependencies on methods running side effects
- It is not possible to completely avoid using some methods that come with react hooks, especially when relying on some third-party libraries
This article is transferred from: https://blog.rxliuli.com/p/1fcd1517c14c4e68b764d7e6df071805/
This site is only for collection, and the copyright belongs to the original author.