laitimes

Solid .js is my ideal React

Author | Nick Scialli

Translated by | Wang Qiang

Planning | Yan Garden

I started using React at work about three years ago. Coincidentally, it was exactly when React Hooks came out. My project code base at the time had a lot of class components that always made me feel clunky.

Let's look at the following example: a counter that is incremented once per second.

It's not a lot of code to write for an auto-incrementing counter. More templates and rituals means more errors and a worse development experience.

Hooks are beautiful, but error-prone

I was very excited when the hooks came along. My counter can be simplified to the following:

Wait, that's actually not right. Our useEffect hook has an old closure around count because we didn't include count in the useEffect dependency array. Omitting variables from dependency arrays is a common mistake with React hooks, and if you forget, there are some linting rules that will warn you.

I'll come back to that later. Now, let's add the missing count variable to the dependency array:

But now we have another problem, look at how well the application works:

People who are proficient in React probably know what's going on because you're battling this problem every day: we create too many intervals (a new interval is created every time we rerun the effect, that is, every time we increase the count interval). There are several ways to solve this problem:

Returns a cleanup function from the useEffect hook for the cleanup interval

Use setTimeout instead of setInterval (or use cleanup functions)

Use the function form of setCount to avoid directly referencing the current value

In fact, either approach works. Here we implement the last option:

Our counter was fixed! Since there is nothing in the dependency array, we have only created one interval. Since we use a callback function for the count setter, we never have a stale closure on the count variable.

This is an artificial example, but unless you've been using React for a while, it's still confusing. Many of us encounter more complex situations every day, and even the most experienced React developers get headaches.

False responsiveness

I think a lot about hooks and wonder why they don't feel right. As a result, I found the answer by exploring solid .js.

The problem with React hooks is that React isn't really responsive design. If linter knows when an effect (or callback or memo) hook is missing a dependency, then why can't the framework automatically detect the dependencies and respond to those changes?

Delve into Solid .js

The first thing to note about Solid is that it doesn't try to reinvent the wheel: it looks a lot like React because React has some glaring patterns: one-way, top-down state; JSX; component-driven architecture.

If we rewrite the Counter component with Solid, we start like this:

So far we've seen a big difference: count is a function. This is called an accessor, and it's an important part of How Solid works. Of course, we don't have anything to say here about incrementing counts at intervals, so let's add it here:

Surely that won't work, right? Won't a new interval be set each time the component renders?

No. That's it.

But why is that? Well, it turns out that Solid doesn't need to rerun the Counter function to re-render the new count. In fact, it doesn't need to rerun the Counter function at all. If we add a console .log statement to the Counter function, we will see that it runs only once.

In our console, there is only one lone log statement:

"The Counter function was called!" In Solid, code doesn't run multiple times unless we explicitly ask for it.

But what about hooks?

So I solved the problem of React useEffect hooks in Solid without having to write something that looked like hooks. We can extend our counter examples to explore solid effects.

What if we want to count the console .log count every time the count increases? Your first reaction might be to use console .log in our functions:

But that doesn't work. Remember that the Counter function only runs once! But we can use Solid's createEffect function to get the desired effect:

It works! And we don't even have to tell Solid that the effect depends on the count variable. This is true responsive design. If the second accessor is called inside the createEffect function, it also makes the effect run.

Some of the more interesting Solid concepts

Responsiveness, not lifecycle hooks

If you've been in the React space for a while, the following code change might really surprise you:

And the code is still valid. Our count signal does not need to exist in a component function, nor does the effect that depends on it. Everything is just part of a reactive system, and "lifecycle hooks" don't actually play much of a role.

Fine-grained DOM updates

My main focus was on Solid's development experience (e.g., it's easier to write error-free code), but Solid's performance has also received a lot of praise. A key source of its powerful performance is its direct interaction with the DOM (no virtual DOM) and performing "fine-grained" DOM updates.

Consider making the following adjustments to our counters:

Run it to get the following logs in the console:

In other words, the only thing that is updated per second is the DOM that contains a small portion of count. Solid doesn't even rerun an earlier console .log in the same div.

Summary

I've enjoyed using React for the past few years; when dealing with the actual DOM, I always feel like it has the right level of abstraction. That being said, I'm also starting to notice that React hooks code often becomes error-prone. I feel that Solid .js uses many of the ergonomic parts of React while minimizing clutter and errors. This article shows you some of the amazing parts of Solid, and if you're interested, I suggest you check out the https://www.solidjs.com and explore the framework for yourself.

https://typeofnan.dev/solid-js-feels-like-what-i-always-wanted-react-to-be/

Read on