🧿 Turn React into SolidJS, update on demand, no more re-render
Tags: react, solidjs, hook, javascript
Published: 2022-04-06 19:32:51

## 1. What is SolidJS?

We all know SolidJS, if not, why are you reading this article!

We all know SolidJS, here is its doc: https://www.solidjs.com

Put it simply, SolidJS is the real "react" version of React, which is completely updated on demand, and where data changes are updated.

For example, a component:

```jsx
function App() {
  const [value, setValue] = useState(0);
  return <div>{value}</div>;
}
```

React calls the entire function of `App` to death (i.e. re-render), while SolidJS only updates the small piece of `value`.

Of course, SolidJS is like this:

```jsx
function App() {
  const [value, setValue] = createSignal(0);
  return <div>{value()}</div>;
}
```

In SolidJS, `App` is called only once during initialization, and is not executed after that.

So JSX in SolidJS is equivalent to "static template", which is only used to describe the UI and will not be called again, and there is no diff.

That is to say, any function executed in `App` or any function executed in JSX will only be triggered once.

## 2. First declare

How to turn React into SolidJS?

Certainly not rename `solid-js` to `react`, nor manually use DOM API to update it without React logic.

It must be stated here:

The following implementation is completely based on the React API, rather than hacking with the DOM API or jQuery, which would be meaningless.

## 3. How to implement it?

### 1. How to update only the small piece of `value()`?

This is the core of the implementation idea, let's just say it - that is to turn `value()` into a component.

Yes, it displays data, but it's actually a component. It's a component that just returns data.

### 2. Why `value()` instead of `value`?

Because we need to know that there is a data here, and it has to be updated later, how do we know?

According to JS syntax, there is no other way than `state.value` (use `getter`) or `value()` (call function).

This is why SolidJS must be written as `value()`. If it is written as `value`, God don't know how to update it, because in the implementation of "static template", the function will not run again.

### 3. Implement a `useSignal` similar to `createSignal`

We want to implement a `useSignal`, similar to SolidJS' `createSignal`, which returns two functions, a getter and a setter.

At the same time, the return of the getter is a component.

```jsx
function useSignal(val) {
  const valRef = useRef(val);
  const update = useRef();

  const Render = () => {
    const [value, setValue] = useState(valRef.current);
    update.current = setValue;
    return value;
  };

  const getter = () => {
    try {
      useState(); // Use this hack to know whether the data is in JSX or read normally elsewhere
      return <Render />;
    } catch (e) {
      return valRef.current;
    }
  };

  const setter = (newVal) => {
    valRef.current = newVal;
    update.current(newVal);
  };

  return [getter, setter];
}
```

The above is a minimal implementation, but it is problematic because the data may be used in multiple places, and the above can only update the data in the last place.

### 4. Data synchronization update version `useSignal`

Collect the update functions with an array of `listeners` and that's it. In fact, this is also the implementation idea of React state managers.

```jsx
function useSignal(val) {
  const valRef = useRef(val);
  const listeners = useRef([]);

  const Render = () => {
    const [value, setValue] = useState(valRef.current);

    useEffect(() => {
      listeners.current.push(setValue);
      return () => {
        listeners.current.splice(listeners.current.indexOf(setValue), 1);
      };
    }, []);

    return value;
  };

  return [
    () => {
      try {
        useState();
        return <Render />;
      } catch (e) {
        return valRef.current;
      }
    },
    (payload) => {
      listeners.current.forEach((listener) => {
        listener((prev) => {
          valRef.current =
            typeof payload === 'function' ? payload(prev) : payload;
          return valRef.current;
        });
      });
    },
  ];
}
```

The above is already a working implementation.

At this point, the core of the story has actually been told.

But if it is to be really used for development needs, there is still a lot of unfinished business.

## 4. What else is there to do?

If it's really "available", it should at least implement:

- createEffect (for listening for data updates)
- createMemo (for creating computed data)
- onMount (for sending requests)
- onCleanup (for unsubscribing)
- What if the data is an object or an array? (This is the most complicated, the above actually only considers primitive data types)
- How to implement conditional operator or function calls in JSX? (The conditional operator or function is only executed once during initialization and cannot respond to change)
- How to respond to HMR? What if the data doesn't appear in JSX for the first time? How to unsubscribe after component unmount...

## 5. Introducing solid-react

There are a bunch of questions written on it, and naturally the answer is ready... This answer is called `solid-react`.

All the problems mentioned above have been solved. If you have a deeper understanding, you can look at the source code.

☞ GitHub: https://github.com/nanxiaobei/solid-react

Here is the API for `solid-react`:

- useSignal (corresponding to createSignal, used to create data)
- useUpdate (corresponding to createEffect, used to monitor data updates)
- useAuto (corresponding to createMemo, used to create computed data)
- useMount (corresponding to onMount, used to send requests)
- useCleanup (corresponding to onCleanup, used to unsubscribe)
- the data is an object or an array (use a proxy to handle this tricky case)
- Run (for conditional operator or functions in JSX, `Run(() => fn(value())`)

Please pay attention to the naming of the API, which is also said: try not to conflict with existing APIs (such as not directly naming `useState` `useMemo`, which will confuse the code), while keeping it concise enough (easy to write) and intuitive (easy to understand).

For specific API introduction, please check README: https://github.com/nanxiaobei/solid-react

In this way, most common development scenarios can already be covered, that is, it can be used for "production".

## 6. Try solid-react

Demo: https://codesandbox.io/s/solid-react-rymhr6?fontsize=14&hidenavigation=1&theme=dark&file=/src/App.js

Here is a demo, you can open the console, click the button to try, and you will find:

Components don't re-render anymore, React is completely SolidJS-style on-demand updates!

`useUpdate` `useAuto` does not need anything like `deps`, its dependencies are automatically learned. And only when dependencies change, they execute again.

Yes, that is to say, you can get rid of Hooks, `useCallback` `useMemo` `deps` `memo`, will it trigger re-render, it's all unnecessary.

A function is a function, an object is an object, and it will not be created again if it is written there.

## 7. What else?

`solid-react` is an experimental project, just to implement an idea, and in fact it is not bad.

`solid-react` tries its best to make it "completely capable", whether it is sending requests or monitoring data, sparrows are small (but delicious) and have all the internal organs.

`solid-react` is a small thing, it may have flaws, of course it can't compare with the maturity of developing directly with React, and it is impossible to compare.

`solid-react` is definitely fine for small demo projects, but I haven't practiced it in big projects, it's good to play with it first, if you're interested.

`solid-react` is more like a concept. It is impossible for React officials to take this road, but thanks to the open source, you can experiment on this road yourself.

`solid-react` works hard to "suffer from Hooks", a general confusion in the industry that has not disappeared for several years (although I feel Hooks are fine)

`solid-react` welcomes those who are interested to try it together and create more possibilities.

Turn React into SolidJS, say goodbye to Hooks, say goodbye to re-render ↓↓↓

https://github.com/nanxiaobei/solid-react

> Some people may want to say, isn't the API of solid-react are Hooks? How to say goodbye to Hooks! In fact, the above is to be compatible with the mixed use of React and solid-react ... Yes, I even considered this situation 🙈