The login
registered
Write an article
Home page
Download the APP

Recoil?

Silly dream beast

Recoil?

When it comes to status managers, wheels are flying around. In the Class era, Redux and Mobx dominated the entire market, and there were hardly any students who hadn’t used Redux. With the birth of Hooks, a new set of wheels emerged, including unstate-next, Constate and so on. Of course, whatever the wheel, the problem is the same: state sharing across components. While solving this core problem, the following features should be met as much as possible:

  • TypeScript support
  • Friendly asynchronous support
  • State interdependence is supported
  • Support for both Class and Hooks components
  • Using a simple

Recoil experience

Let’s take a look at Recoil, facebook’s official status manager solution.

The preparatory work

To use Recoil, we need to wrap a RecoilRoot in the outermost layer of the project, which, like most state managers, uses context to pass data across components.

import React from 'react';
import { RecoilRoot } from 'recoil';

function App() {
  return (
    <RecoilRoot>
        ...
    </RecoilRoot>
  );
}

Copy the code

Sharing across component states

States are easiest to define and use. In Recoil, a state is defined using Atom.

const inputValueState = atom({
  key: "inputValue",
  default: ""
});

Copy the code

As shown in the code above, we define an inputValue state whose default value is an empty string. Note the key field, which should be globally unique. This key is mainly used for debugging, persisting data (a unique identifier for data recovery), and making it easy to see the global Atoms tree.

Consuming state is also simpler, with useRecoilState consuming state.

import React from "react"; import { useRecoilState } from "recoil"; import { inputValue } from ".. /store"; const InputA = () => { const [value, setValue] = useRecoilState(inputValueState); return <input value={value} onChange={e => setValue(e.target.value)} />; }; export default InputA;Copy the code

Isn’t that easy? This is the basic usage of Recoil. I’ve written a demo here, so you can try it out.


image

</noscript>


image

State interdependence

Some state depends on some other state, and then you define that state using selector. For example, we need to define a new state, filterdInputValue, which is the value after filtering the numbers in inputValue.

const filterdInputValue = selector({ key: "filterdInputValue", get: Const inputValue = get(inputValueState); const inputValue = get(inputValueState); return inputValue.replace(/[0-9]/ig, ""); }});Copy the code

Selector is pretty simple, just to implement state dependency. You can try it out in this demo.


image

</noscript>


image

Asynchronous support

Good asynchronous request support is essential for the state manager. Recoil provides a useRecoilValueLoadable to handle asynchronous requests. Go straight to the example:

const currentUserNameQuery = selector({ key: "CurrentUserName", get: async () => { const response = await queryUserInfo(); return response.name; }});Copy the code

We need to define the asynchronous state by selector. If get is a Promise, that state is asynchronous, and we need to use useRecoilValueLoadable to consume that state.

const UserName = () => {
  const userNameLoadable = useRecoilValueLoadable(currentUserNameQuery);
  switch (userNameLoadable.state) {
    case "hasValue":
      return <div>{userNameLoadable.contents}</div>;
    case "loading":
      return <div>Loading...</div>;
    case "hasError":
      throw userNameLoadable.contents;
  }
};

Copy the code

As you can see from the above example, the state returned by useRecoilValueLoadable can be read from the state field to read the status of the asynchronous request. I wrote a demo so you can try it out.


image

</noscript>


image

Of course, using useRecoilValueLoadable to consume asynchronous state is more in line with our current habits. Suspense may be the direction, but it’s not too good to use!

const UserName = () => { const userName = useRecoilValue(currentUserNameQuery); return <>{userName}</> } }; function MyApp() { return ( <React.Suspense fallback={<div>Loading... </div>}> <UserName /> </React.Suspense> ); }Copy the code

evaluation

advantages

  • It would be a good thing if state managers were everywhere.
  • React Concurrent mode is well supported.

insufficient

Recoil is still under development, and documentation is not complete. Based on the situation, here are my feelings.

1. Ts is not implemented and currently not supported

I was surprised to find this, but I didn’t find it until I wrote this article. It’s weird. It should be natural for Recoil to support typescript. Maybe @types/ Recoil will be needed later.

2. Currently, no Class component consumption status is supported.

This feature should be a must and should not completely discard the Class component. The next version will definitely support this feature. Low cost of implementation, it would be anti-human not to support it.

3. There are too many apis, which have some starting costs.


image

</noscript>


image

There are 19 different apis, so it’s a bit complicated. It feels like a lot of things can be combined, like Atom and selector into one and so on (or maybe I’m not thinking too far). It is suggested that officials consider streamlining. It is a very simple thing, but it is too complicated.

4. Consumption is complicated

When we need to consume a state, we need to import two things, which is tedious.

import { useRecoilState } from "recoil"; import { inputValueState } from ".. /store"; / / usage useRecoilState (inputValueState);Copy the code

It should be possible to consume the string key directly, but this is the same as the Redux problem. Ts is not supported.

import { useRecoilState } from "recoil";

useRecoilState('inputValueState');

Copy the code

Either way, importing two things is not a good use.

5. Not enough highlights

I didn’t see anything that caught my eye, I didn’t use impulse. Wait and see

Afterword.

Recoil overall, relatively moderate, need to wait and see the development. Another recommendation is hox, the simplest React state manager I’m currently using. It has only one API, is very intuitive, has no overhead costs, and fully embraces Hooks.