This is the 10th day of my participation in Gwen Challenge

What is the Hook

Hook is a new feature in React 16.8. It lets you use state and other React features without having to write a class.

  • Totally optional. You can try hooks in some components without rewriting any existing code. But you don’t have to learn or Hook now if you don’t want to.
  • 100% backward compatible. Hooks do not contain any destructive changes.
  • Now available. Hook was released in V16.8.0.

Basic Hook (3)

useState:

import React, { useState } from 'react';
function Example() {
  // Declare a new state variable called "count"
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={()= > setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
Copy the code

parameter

The only argument to useState is the initial state. State doesn’t have to be an object — it could be if you need it. The initial state parameter is only used for the first rendering.

The return value

UseState returns a pair of values: the current state and a function that lets you update it, which you can call in an event handler or some other place.

Read the state

// Read state in class
<p>You clicked {this.state.count} times</p>
// Reads state in the function
<p>You clicked {count} times</p>
Copy the code

Update the state

    // Update state in class
    <button onClick={() = > this.setState({ count: this.state.count + 1 })}>
    Click me
  </button>
  
    // Update state in function
  <button onClick={()= > setCount(count + 1)}>
    Click me
  </button>
Copy the code

Use multiple state variables

function ExampleWithManyStates() {
  // Declare multiple state variables
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'learning Hook' }]);
}
Copy the code

useEffect:

import React, { useState, useEffect } from 'react';
function Example() {
  const [count, setCount] = useState(0);
  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() = > {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={()= > setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
Copy the code

UseEffect is an Effect Hook that gives function components the ability to manipulate side effects. It serves the same purpose as componentDidMount, componentDidUpdate, and componentWillUnmount in the Class component, but has been consolidated into an API.

UseEffect Hook can be regarded as a combination of componentDidMount, componentDidUpdate and componentWillUnmount.

parameter

  • The first argument is a function that is a side effect of the first render and subsequent updates.
    • This function may have a return value, and if it does, the return value must be a function that is executed when the component is destroyed.
  • The second argument, optional, is an array containing some of the side effect properties used in the first function.

When does the useEffect run

By default, it is executed after the first rendering and after each update. This can be interpreted as an effect that happens “after each render”, without worrying about “mount” or “update”. React ensures that the DOM is updated every time an Effect is run.

If we want to execute only when specified, we can pass the second argument to useEffect and use the second argument to tell React that the side effect function we passed (the first argument) will be executed only if the value of this argument changes.

Such as:

useEffect(() = > {
  document.title = `You clicked ${count} times`;
}, [count]); // Document. title is reexecuted only when count changes
Copy the code

If you want to execute effect once (only when the component is mounted and unmounted), you can pass an empty array ([]) as the second argument. This tells React that your effect doesn’t depend on any value in props or state, so it never needs to be repeated.

The most common scenario for requesting data in componentDidMount is to useEffect to introduce external dependencies to determine when there is no data or parameter change.

useEffect(() = > {
  fetchData(id);
}, [id]);
Copy the code

React teams will tend to make no distinction between componentDidMount and componentDidUpdate. That is, stop distinguishing whether components are already mounted and use a unified API for state management.

How to remove an effect

React cleans up components when they are unmounted. In class components, we usually clean up side effects during the componentWillUnmount life cycle, such as timers, shortcuts, event listeners, etc.

In useEffect, an optional function is provided to implement it: If your effect returns a function, React will call it when a cleanup operation is performed.

useEffect(() = > {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () = > {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
});
Copy the code

Unlike componentDidMount or componentDidUpdate, effects scheduled with useEffect don’t block the browser update screen, making your application seem more responsive. In most cases, effects do not need to be executed synchronously. In individual cases (such as measuring layout), there is a separate useLayoutEffect Hook for you to use, with the same API as useEffect.

useContext

// a.js
const MyContext = createContext(null);
// 
const value = useContext(MyContext);
Copy the code

Context is designed to share data that is “global” to a component tree, such as the currently authenticated user, topic, or preferred language. You can avoid passing props through intermediate elements.

UseContext receives a context object (the return value of react. createContext) and returns the current value of the context. The current context value is determined by the < MyContext.provider > value prop of the upper-layer component closest to the current component.

The context API usage reference documentation zh-hans.reactjs.org/docs/contex…

Additional hooks (7)

useReducer

It receives a Reducer of the form (state, action) => newState and returns the current state and its accompanying dispatch method.

useCallback

const memoizedCallback = useCallback(
  () = > {
    doSomething(a, b);
  },
  [a, b],
);
Copy the code

Returns a Memoized callback function.

Passing the inline callback function and the array of dependencies as arguments to useCallback returns the Memoized version of the callback function, which is updated only when a dependency changes. This is useful when you pass callback data to child components that are optimized and use reference equality to avoid unnecessary rendering (such as shouldComponentUpdate).

UseCallback (fn, deps) is equivalent to useMemo(() => FN, deps).

useMemo

const memoizedValue = useMemo(() = > computeExpensiveValue(a, b), [a, b]);
Copy the code

Returns an memoized value.

You pass in the create function and the dependency array as arguments to useMemo, which recalculates memoized values only when a dependency changes. This optimization helps avoid costly calculations every time you render.

Remember that functions passed into useMemo are executed during rendering. Please do not perform non-rendering operations inside this function. Operations such as side effects are used by useEffect, not useMemo.

If the dependency array is not provided, useMemo evaluates the new value each time it renders.

userRef

const refContainer = useRef(initialValue);
Copy the code

UseRef returns a mutable ref object whose.current property is initialized as the passed parameter (initialValue). The ref object returned remains constant throughout the life of the component.

useImperativeHandle

UseImperativeHandle allows you to customize the instance value exposed to the parent component when using a ref.

useLayoutEffect

Its function signature is the same as useEffect, but it calls Effect synchronously after all DOM changes. You can use it to read DOM layouts and trigger rerenders synchronously. The update schedule inside useLayoutEffect is refreshed synchronously before the browser performs the drawing.

userDebugValue

UseDebugValue can be used to display tags for custom hooks in the React developer tool.

Customize the Hook

A custom Hook is a function whose name starts with “use” that can call other hooks from within.

Unlike the React component, custom hooks do not need to have a special identity. We are free to decide what its arguments are and what it should return (if necessary). In other words, it’s just like a normal function. But its name should always start with use, so it can be seen at a glance that it meets Hook rules.

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);
  // ...
  return isOnline;
}
Copy the code

Hook usage rules

Hooks are JavaScript functions, but there are two additional rules for using them:

  • A Hook can only be called on the outermost layer of a function. Do not call in loops, conditional judgments, or subfunctions.
  • You can only call a Hook in the React function component or a custom Hook. Do not call it from another JavaScript function.

Why is that?

 // ------------
// First render
// ------------
useState('Mary')           // 1. Initialize state of variable name with 'Mary'
useEffect(persistForm)     // 2. Add effect to save form action
useState('Poppins')        // 3. Initialize the state of the surname variable with 'Poppins'
useEffect(updateTitle)     // 4. Add effect to update the title
// -------------
// Secondary render
// -------------
useState('Mary')           // 1. Read state with variable name (argument ignored)
useEffect(persistForm)     // 2. Replace save form effect
useState('Poppins')        // 3. Read the state of a variable named surname (parameter ignored)
useEffect(updateTitle)     // 4. Replace the effect that updates the title
// ...
Copy the code

React depends on the sequence of Hook calls to determine which state corresponds to which useState. Therefore, ensure that the sequence of Hook calls in each rendering is the same. If you put one of these hooks in a conditional statement, the order of execution may change and React may not properly associate the internal state with the corresponding Hook.

useState('Mary')           // 1. Read state with variable name (argument ignored)
// Using Hook in conditional statements violates the first rule
if(name ! = =' ') {        // If name is null, this Hook is ignored, resulting in subsequent order changes
    useEffect(function persistForm() {
        localStorage.setItem('formData', name);
    });
}
useState('Poppins')        // 2 (previously 3). Failed to read state of surname variable
useEffect(updateTitle)     // 3 (previously 4) Failed to replace effect updating title
Copy the code