React advanced -- Hook learning notes

Posted by JStefan on Mon, 31 Jan 2022 14:51:08 +0100

1. Hook introduction

Hook is a new feature added in React 16.8.0. You can use state and other React features in function components.

✌️ Hook usage rules:

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

  • Hook can only be called on the outermost layer of a function. Do not call in loops, conditional judgement, or subfunctions.
  • You can only call Hook in function components of React, not in other JavaScript functions. (there is another place to call hook -- custom hook)

Here are some commonly used hooks.

2. useState

useState allows function components to have state and read and write state data.

const [xxx, setXxx] = useState(initValue); // Destructuring assignment 

📐 useState() method

Parameters:

The specified value is cached internally during the first initialization. It can be assigned with numbers or strings as needed, not necessarily objects.

If you want to store two different variables in state, just call useState() twice.

Return value:

An array containing two elements. The first is the internal current state value and the second is a function to update the state value. It is generally obtained directly by deconstruction assignment.

📐 How to write setXxx()

setXxx(newValue): the parameter is a non function value, which directly specifies a new status value and internally overwrites the original status value.

SetXXX (value = > newvalue): the parameter is a function that receives the original status value and returns a new status value, which is used internally to overwrite the original status value.

📐 Complete example

const App = () => {
    const [count, setCount] = useState(0);

    const add = () => {
        // The first way to write
        // setCount(count + 1);
        // The second way to write
        setCount(count => count + 1);
    };

    return (
        <Fragment>
            <h2>The current summation is:{count}</h2>
            <button onClick={add}>Point me+1</button>
        </Fragment>
    );
};

Declare a state variable called count and set it to 0. React will remember its current value when rendering repeatedly and provide the latest value to our function. We can update the current count by calling setCount.

In the function, we can directly use count:

<h2>The current summation is:{count}</h2>

Update state:

setCount(count + 1);
setCount(count => count + 1);

📐 Use multiple state variables

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

📌 Instead of having to use multiple state variables, you can still group the relevant data. However, unlike this in class Updating the state variable in setstate and useState is replacement. Not a merger.

3. useEffect

useEffect can perform side-effect operations in function components (used to simulate life cycle hooks in class components).

Side effects in React:

  • Send ajax request for data acquisition
  • Set subscription / start timer
  • Manually change the real DOM

📐 Usage rules

useEffect(() => {
    // Any operation with side effects can be performed here
    // Equivalent to componentDidMount()
    return () => {
        // Execute before component uninstallation
        // Do some finishing work here, such as clearing timer / unsubscribing, etc
        // Equivalent to componentWillUnmount()
    };
}, [stateValue]); // Listen for stateValue
// If the array is omitted, all States are detected, and the callback function is called again when the state is updated
// If [] is specified, the callback function will execute only once after the first render()

useEffect can be regarded as a combination of the following three functions:

  • componentDidMount()
  • componentDidUpdate()
  • componentWillUnmount()

📐 Run Effect every time you update

// ...
useEffect(() => {
    // ...
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
        ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
});

Before calling a new effect, the previous effect will be cleaned up. The following lists a possible call sequence of subscription and unsubscribe operations by time:

// Mount with { friend: { id: 100 } } props
ChatAPI.subscribeToFriendStatus(100, handleStatusChange);     // Run the first effect

// Update with { friend: { id: 200 } } props
ChatAPI.unsubscribeFromFriendStatus(100, handleStatusChange); // Clear previous effect
ChatAPI.subscribeToFriendStatus(200, handleStatusChange);     // Run the next effect

// Update with { friend: { id: 300 } } props
ChatAPI.unsubscribeFromFriendStatus(200, handleStatusChange); // Clear previous effect
ChatAPI.subscribeToFriendStatus(300, handleStatusChange);     // Run the next effect

// Unmount
ChatAPI.unsubscribeFromFriendStatus(300, handleStatusChange); // Clear last effect

📐 Performance optimization by skipping Effect

If some specific values do not change between two re renderings, you can tell React to skip the call to effect by passing the array as the second optional parameter of useEffect:

useEffect(() => {
    document.title = `You clicked ${count} times`;
}, [count]); // Update only when count changes

If the value of count is 5 and the count is still equal to 5 when the component is re rendered, React will compare [5] of the previous rendering with [5] of the next rendering. Because all elements in the array are equal (5 = = = 5), React will skip this effect, which optimizes the performance.

When rendering, if the value of count is updated to 6, react will compare the elements in the array [5] of the previous rendering with the elements in the array [6] of this rendering. This time because 5== 6. React will call effect again.

📌 If there are multiple elements in the array, React will execute effect even if only one element changes.

The same applies to the effect with clear operation:

useEffect(() => {
    function handleStatusChange(status) {
        setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
        ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
}, [props.friend.id]); // Only in props friend. Re subscribe when ID changes

📐 Separation of concerns using multiple effects

function FriendStatusWithCounter(props) {
    const [count, setCount] = useState(0);
    useEffect(() => {
        document.title = `You clicked ${count} times`;
    });

    const [isOnline, setIsOnline] = useState(null);
    useEffect(() => {
        function handleStatusChange(status) {
            setIsOnline(status.isOnline);
        }

        ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
        return () => {
            ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
        };
    });
    // ...
}

📐 Complete example

import React, { useState, Fragment, useEffect } from 'react';
import ReactDOM from 'react-dom';

const App = () => {
    const [count, setCount] = useState(0);

    useEffect(() => {
        let timer = setInterval(() => {
            setCount(count => count + 1);
        }, 500);
        console.log('@@@@');
        return () => {
            clearInterval(timer);
        };
    }, [count]);
    // Detect the change of count and output '@ @ @' every time
    // If it is [] '@ @ @' will be output only once

    const add = () => {
        setCount(count => count + 1);
    };

    const unmount = () => {
        ReactDOM.unmountComponentAtNode(document.getElementById('root'));
    };

    return (
        <Fragment>
            <h2>The current summation is:{count}</h2>
            <button onClick={add}>Point me+1</button>
            <button onClick={unmount}>Uninstall components</button>
        </Fragment>
    );
};

export default App;

4. useRef

useRef can store / find labels or any other data in a function component. Save label object, function and react Createref().

const refContainer = useRef(initialValue);

useRef returns a mutable ref object whose The current property is initialized to the passed in parameter (initialValue). The returned ref object remains unchanged throughout the life cycle of the component.

📌 useRef will not notify you when the contents of ref objects change. Change The current property does not cause the component to re render.

import React, { Fragment, useRef } from 'react';

const Demo = () => {
    const myRef = useRef();

    //Callback prompting for input
    function show() {
        console.log(myRef.current.value);
    }

    return (
        <Fragment>
            <input type="text" ref={myRef} />
            <button onClick={show}>Click to display the value</button>
        </Fragment>
    );
};

export default Demo;

5. Hook rules

Use Hook only at the top

Do not call Hook in loops, conditions or nested functions, and call Hook at the top of the React function.

If you want to execute an effect conditionally, you can put the judgment inside the Hook:

useEffect(function persistForm() {
    // 👍  Place conditional judgment in effect
    if (name !== '') {
        localStorage.setItem('formData', name);
    }
});

Call Hook only in React function

Do not call Hook in the ordinary JavaScript function. sure:

  • Calling Hook in the function component of React
  • Call other Hook in custom Hook

Welcome to my blog:
https://lzxjack.top/

Topics: Javascript Front-end React hook