Hi Daniel, how about today we talk about how to use state safely?

Daniel: Safe? Is using React Hooks state still dangerous? X﹏X tense ~

Relax, relax. I’ll give you an example of safety and it’ll make sense. Without the help of examples, it is difficult to explain clearly at a draught. Maybe it is my ability of expression.

Daniel: Ok. Are there people here who don’t know what React Hooks are?

Maybe there are some students still don’t understand, then I will simply introduce (suddenly there is a suspected of – ヘ (_ |) :

React Hooks are great. They allow you to implement stateful components using pure functions, so that you no longer have to choose between stateful and stateless components, thus switching between pure function and class implementations. Why React Hooks? 😬).

Once you’re on the road to React Hooks, you get all sorts of weird questions.

It’s normal, a new thing is born, with all sorts of problems, and then it escalates and grows in the fight, and eventually becomes…

Daniel: Hey, don’t get sidestepped

🤪 if you’ve read the official documentation on React Hooks and seen some of the examples, you might think that it’s pretty easy, just change to useState to useState.

But the moment you let your guard down, “danger” is lurking around the corner.

Daniel: Nervous? What danger? You’re not going to lose your virginity

😅 forehead ~ ~

For the state value, you may get an old value that is not what you expected, that is, not the latest state value.

You need to be awake all the time to get around these “dangers”.

Daniel: 😵

I’m going to give you an example right now.

Here comes the chestnut: When you fill in some information on a form and then leave it, you want it to be automatically saved as a draft so you can go back to it the next time you come in and save yourself the trouble of filling it out again.

The following is a simplified version of the implementation:

import React, { useState, useEffect } from "react";

export const UseStateDemoComp1 = () => {
  const [name, setName] = useState('daniel');

  useEffect(function() {
    return () => {
      saveDraft()
    }
  }, [])

  function saveDraft() {
    console.log('Save Draft:', name);
  }

  return (
    <div>
      <form>
        <input value={name} onChange={e => setName(e.target.value)}></input>
      </form>
    </div>
  );
};

Copy the code

Yesterday, the code seems to be fine.

The function passed to useEffect returns a function equivalent to the original componentWillUnmount lifecycle method, which is called only when the component is about to be destroyed. Perform some logic in this method, where you call the saveDraft method, get the value of name state, and save it.

Have you identified the problem? If not, let’s go straight to a GIF and see what the problem is:

Clicking the Toggle button destroys the component, so the destroy action is triggered. As you can see in the driven image, we filled in “Sarah”, but in the destruction execution method, the value is “Daniel”.

Daniel: Why is that? Shouldn’t it be the latest value? 😶

Because useEffect relies on an empty array, it is executed only once in the entire component life cycle, after the component has completed rendering for the first time. The state used in useEffect is the latest state, which can be interpreted as a snapshot. No matter how many times the component is re-rendered over time, it will not change the value of state inside because it is only a snapshot of the time

Some of you might say, just add name to the useEffect dependent array. As follows:

useEffect(function() {
    return () => {
      saveDraft()
    }
}, [name])
Copy the code

It looks like it meets the requirements, but there’s still a problem. Because I only want to save when the component exits, but now the effect is that the value of the form field will be saved whenever it changes, and saving becomes very frequent.

Daniel: So you’re saying that the React Hooks can’t do anything about it?

Of course not. UseRef and useEffect can do this. How do you do that? Let’s use our own brains. When you implement it, your code is verbose and unreadable.

Daniel: Ok, please start your performance

😎 With the above example, here is a description of using state safely:

“Using state safely means that whenever and how you read the value of state, it always fits your expectations, always the most recent value, and you don’t have to be careful about whether it’s an old value that hasn’t been updated.”

Official offers the ability to customize Hooks, which are intended to continue to be improved through community efforts.

Next we use useSingleState instead of useState, using nice-hooks, an open source project for third-party custom hooks

import React, { useEffect } from "react";
import { useSingleState } from "nice-hooks";

export const DemoComp1 = () => {
  const [state, setState] = useSingleState({
    name: 'daniel'
  });

  useEffect(function() {
    return () => {
      saveDraft()
    }
  }, [])

  function saveDraft() {
    console.log('Save Draft:', state.name);
  }

  return (
    <div>
      <form>
        <input value={state.name} onChange={e => setState({name: e.target.value})}></input>
      </form>
    </div>
  );
};

Copy the code

Let’s take a GIF and see what it looks like. Perfect ~

UseSingleState hook: It uses state in a similar way to the class forms this.state and this.setState, so it’s pretty easy to get started. The most important thing is that it can safely use state and has callback capabilities.

Finally, we use the hook of useLifeCycle to further improve the code. Ok, doesn’t the following code feel much better than using the official hooks directly?

import React from "react";
import { useSingleState, useLifeCycle } from "nice-hooks";

export const DemoComp1 = () => {
  const [state, setState] = useSingleState({
    name: 'daniel'
  });

  useLifeCycle({
    willUnmount() {
      saveDraft()
    }
  })

  function saveDraft() {
    console.log('Save Draft:', state.name);
  }

  return (
    <div>
      <form>
        <input value={state.name} onChange={e => setState({name: e.target.value})}></input>
      </form>
    </div>
  );
};

Copy the code

How time flies, it’s time to say goodbye again.

If you think this article is ok, please give it a thumbs up.

If you think nice-hooks are good, add them.

ByeBye!


Keywords: react, hooks, nice-hooks