Address: Medium.com/@ryardley/r…

原 文 : Tinder (Github)

Address: github.com/answershuto…

Please reprint from famous sources

I am a big fan of the hooks API, however it can impose some strange constraints on your use, so I use a model in this article to show the principles to those who want to use the new API but have trouble understanding its rules.

Warning: Hooks are experimental

The Hooks API mentioned in this article is experimental, but if you need the stable React API documentation, you can find it here.

Decrypt how Hooks work

I’ve seen some students struggling with the “magic” in the new Hooks API, so I’m going to try to explain, at least on the surface, how it works.

The rules of the Hooks

The React Core team put forward two main rules in the Hooks proposal that you must follow when using them.

  • Do not call Hooks in loops, conditions, or nested functions
  • * Hooks are called in React functions

The latter, I think, is obvious. To add behavior to a component, you need to associate the behavior with the component in a functional way.

With the former, I think it’s confusing because it doesn’t seem natural to program with the API, but that’s what I’m going to lasso today.

Hooks state management is array-dependent

To give you a clearer model, let’s take a look at what a simple implementation of Hooks might look like.

It is important to note that this section is only one possible implementation of the API, so that readers can better understand it. It’s not how the API actually works internally, and it’s a proposal that’s subject to change in the future.

How should we implement “useState()”?

Let’s look at an example to understand how states might work.

Let’s start with a component:

The code address

/ *, https://github.com/answershuto * /
function RenderFunctionComponent() {
  const [firstName, setFirstName] = useState("Rudi");
  const [lastName, setLastName] = useState("Yardley");

  return (
    <Button onClick={()= > setFirstName("Fred")}>Fred</Button>
  );
}
Copy the code

The idea behind the Hooks API is that you can return a setter function as the second argument to the Hooks function, and use that function to control the Hooks managed robustness.

So what can React do with this?

First, let’s explain how it works inside React. The following steps are performed when the execution context renders a particular component. This means that the data is stored independently of the components. This state cannot be shared with other components, but it has a separate scope that reads data when it needs to be rendered.

(1) Initialization

Create two empty arrays “setters” and “state”

Set cursor to 0

(2) First rendering

First execution of a component function

Whenever useState() is called, if it is first rendered, it will push a setter method (bound to the cursor position) into the setters array, and it will also put another corresponding state into the state array.

(3) Subsequent rendering

Each subsequent rendering resets the position of the cursor and reads the corresponding value from each array.

(4) Handling events

Each setter will have a reference to the corresponding pointer position, so any call to the setter will be triggered to change the corresponding value in the state array.

And the underlying implementation

Here is an example code:

The code address

let state = [];
let setters = [];
let firstRun = true;
let cursor = 0;

function createSetter(cursor) {
  return function setterWithCursor(newVal) {
    state[cursor] = newVal;
  };
}

/ *, https://github.com/answershuto * /
// This is the pseudocode for the useState helper
export function useState(initVal) {
  if (firstRun) {
    state.push(initVal);
    setters.push(createSetter(cursor));
    firstRun = false;
  }

  const setter = setters[cursor];
  const value = state[cursor];

  cursor++;
  return [value, setter];
}

/ *, https://github.com/answershuto * /
// Our component code that uses hooks
function RenderFunctionComponent() {
  const [firstName, setFirstName] = useState("Rudi"); // cursor: 0
  const [lastName, setLastName] = useState("Yardley"); // cursor: 1

  return (
    <div>
      <Button onClick={()= > setFirstName("Richard")}>Richard</Button>
      <Button onClick={()= > setFirstName("Fred")}>Fred</Button>
    </div>
  );
}

// This is sort of simulating Reacts rendering cycle
function MyComponent() {
  cursor = 0; // resetting the cursor
  return <RenderFunctionComponent />; // render
}

console.log(state); // Pre-render: []
MyComponent();
console.log(state); // First-render: ['Rudi', 'Yardley']
MyComponent();
console.log(state); // Subsequent-render: ['Rudi', 'Yardley']

// click the 'Fred' button

console.log(state); // After-click: ['Fred', 'Yardley']
Copy the code

Why does order matter?

What happens if we change the order of Hooks in the render cycle based on some external condition or the state of the component?

Let’s do something the React team is not allowed to do.

The code address

let firstRender = true;

function RenderFunctionComponent() {
  let initName;
  
  if(firstRender){
    [initName] = useState("Rudi");
    firstRender = false;
  }
  const [firstName, setFirstName] = useState(initName);
  const [lastName, setLastName] = useState("Yardley");

  return (
    <Button onClick={()= > setFirstName("Fred")}>Fred</Button>
  );
}
Copy the code

We called the useState function in a conditional statement, and let’s look at the damage it did to the entire system.

First rendering of a bad component

At this point, our variables firstName and lastName still contain the correct data, so let’s move on to see what happens in the second render.

Bad second render

Now the firstName and lastName variables are both set to “Rudi”, which is inconsistent with our actual storage state.

The use of this example is obviously incorrect, but it shows us why we must use the React team’s rules to use Hooks.

The React team created this rule because using the Hooks API without following it could cause data problems.Copy the code

Consider that Hooks maintain arrays of columns, so you should not violate these rules

So you should now clear why you should not use Hooks in conditional statements or loops. Because we maintain a pointer “cursor” that points to an array, if you change the call order inside render, the pointer “cursor” will not match the correct data and your call will not point to the correct data or handle.

So, one trick is to think about Hooks as arrays that need to be managed by a consistent matching cursor. If this is done, it will work in any way.

conclusion

Hopefully, I’ve given you a clearer mental model of what’s going on underneath the new Hooks API. Keep in mind that the real value is being able to keep the focus together and be careful about the order of it, and that using the Hooks API is highly rewarding.

Hooks are a very useful plugin for the React component, which is why people are so excited about them. If you have a mental model of this state as a set of arrays in your mind, then you will find that there is no breaking of its rules in use.

I hope to look at the useEffects useEffects method again in the future and try to compare it to the React lifecycle.

This article is an online document, so if you’d like to contribute or if there are any errors, please feel free to contact me.

You can find me on Twitter (Rudi Yardley) or on Github.

Dye devoted to translation: github.com/answershuto