Currently, Hooks are the most popular concept in React. Before you read this article, hopefully you already know what basic Hooks are.

Here is a simple usage scenario

react hooks

useState

UseState is a react hook function that declares state variables. The useState function takes our initial state and returns an array in which item [0] is the current state value and item [1] is a method function that can change the state value.


import React, { useState} from 'react';
function Example() {
     //useState is used to declare, read, use (modify)
    const [count, setCount] = useState(0) // Array structure
    const [age, setAge] = useState(18)
    const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
    return (
        <div>
            <button onClick={()= > { setCount(count + 1) }}>count</button>
            <button onClick={()= > { setAge(age + 1) }}>age</button>
        </div>
    );
}

export default Example;

Copy the code

Based on the usage of useState, we tried to implement a useState ourselves


var _state; // Store the state outside
function useState(initialValue) {
  _state = _state | initialValue; // If there is no _state, it is the first time. Copy initialValue to it
  function setState(newState) {
    _state = newState;
    render();
  }
  return [_state, setState];
}

Copy the code
useEffect

UseEffect allows you to handle lifecycle events directly within a function component. If you’re familiar with React class lifecycle functions, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount

UseEffect Is used with caution

  • There are two parameters, callback and Dependencies array
  • If dependencies do not exist, the callback will be executed for each render
  • If dependencies exist, callback is executed only if it changes
import React, { useEffect, useState } from 'react';
import ReactDOM from 'react-dom';

function useEffectTest() {
  useEffect((a)= > {
      
    // By default, this function is called after every render
    console.log('render! ');

    // To implement componentWillUnmount,
    // Return a function at the end
    // React calls this method before the function component is uninstalled
    // This is called cleanup to indicate the purpose of this function,
    // But you can also return an arrow function or give it another name.
    return function cleanup () {
        console.log('unmounting... '); }})return "useEffectTest";
}
Copy the code

If you want effect to run less often, you can provide a second parameter-value array. Think of them as dependencies of the effect. If one of the dependencies has changed since the last time, Effect will run again.

const [value, setValue] = useState(0);

useEffect((a)= > {
  // Update only when value changes
  console.log(value);
}, [value]) 
Copy the code
useContext

UseContext can implement shared state. The biggest change is that we don’t have to wrap Children when we use Counter. Let’s say we create a context that has a state called count, And a method that changes count, setCount

Create context


import React, { createContext, useState } from 'react';
import { Counter } from './Counter'
export const CountContext = createContext()
function Example2() {
    const [count, setCount] = useState(0)
    return (
        <div>
            <CountContext.Provider value={count,setCount}>
                <Counter />
            </CountContext.Provider>
        </div>
    )
}

export default Example2;

Copy the code

Use context

import React, { useContext} from 'react'; import {CountContext} from './Example2' export function Counter() { const {count,setCount} = useContext(CountContext) <h2>{count}</h2> <button onClick={() => {setCount(count + 1)}}>count</button>)}Copy the code
useReducer

The core concept of Redux is that components emit actions to communicate with the state manager. After the state manager receives the action, it calculates the new state using the Reducer function

  • Reducer is a function (state, action) => newState: Receive the state of the current application and the triggered action actions, calculate and return the latest state.
import React, { useReducer } from 'react';
function reducer(state, action) {
    switch (action.type) {
        case 'add':
            return { count: state.count + 1 };
        case 'sub':
            return { count: state.count - 1 };
        default:
            return state
    }
}
function Example2() {
    const initialState = { count: 0 };
    const [state, dispatch] = useReducer(reducer,initialState)
    return (
        <div>
            <p>You clicked {state.count} times</p>
            <button onClick={()= > { dispatch({ type: 'add'})}}>add</button>
            <button onClick={()= > { dispatch({ type: 'sub'})}}>sub</button>
        </div>)}export default Example2;
Copy the code
useMemo

React 16.8.0 useMemo()

React.memo() determines whether a function component’s rendering is repeated

UseMemo () defines whether a piece of function logic is executed repeatedly

UseMemo (() => fn, inputs) has the same effect as useCallback(FN, inputs)

const increase = useMemo((a)= > {
    if(value > 2) return value + 1;
}, [value]);
Copy the code
useRef

The node that acquires the DOM element acquires the store of shared data between the instance render cycles of the child component (state cannot store data across render cycles because saving state triggers component rerendering).

import React, { useEffect, useRef } from 'react';
function App() {
  const h1Ref = useRef();
  useEffect((a)= > {
    console.log('useRef')
    console.log(h1Ref.current)
  }, [])
  return <h1 ref={h1Ref}>Hello World!</h1>
}
export default App;
Copy the code
useCallback
  • Creating a cache of callback methods allows us to pass child nodes as props without changing them, avoiding unnecessary rendering.

  • Inputs: Determine whether to return the old method stored in their inputs, or to return the new method and record their inputs.

import React, { useState, useCallback, useEffect } from 'react';

const set = new Set(a);function Callback() {
    const [count, setCount] = useState(1);
    const [val, setVal] = useState(' ');

    const callback = useCallback((a)= > {
        console.log(count);
    }, [count]);
    set.add(callback);


    return <div>
        <h4>{count}</h4>
        <h4>{set.size}</h4>
        <div>
            <button onClick={() => setCount(count + 1)}>+</button>
            <input value={val} onChange={event => setVal(event.target.value)}/>
        </div>
    </div>;
}

export default function Parent() {
    const [count, setCount] = useState(1);
    const [val, setVal] = useState('');

    const callback = useCallback(() => {
        return count;
    }, [count]);
    return <div>
        <h4>{count}</h4>
        <Child callback={callback}/>
        <div>
            <button onClick={() => setCount(count + 1)}>+</button>
            <input value={val} onChange={event => setVal(event.target.value)}/>
        </div>
    </div>;
}

function Child({ callback }) {
    const [count, setCount] = useState(() => callback());
    useEffect(() => {
        setCount(callback());
    }, [callback]);
    return <div>
        {count}
    </div>
}


Copy the code
useImperativeMethods

Taking a ref as an argument is essentially a useLayoutEffect call. The main thing is to mount content on the ref passed in externally, similar to how ref mounts to the ClassComponent

functionFancyInput(props, ref) { const inputRef = useRef(); useImperativeMethods(ref, () : ({ focus: () : { inputRef.current.focus(); }}));return<input ref={inputRef} ... / >; } FancyInput = forwardRef(FancyInput);Copy the code

React-Redux Hooks

useSelector
  • UseSelector is used to extract values from the state stored by Redux and subscribe to that state, basically similar to the mapStateToProps function implemented in hooks

  • First, the ownProps API is no longer provided, and you should use useCallback or useMemo to get them through custom logic

  • Second, the second argument to useSelector() also relies on arrays, just like useEffect. If the second parameter is not provided, it is recalculated every time the component is updated; If a dependent array is provided, recalculation is triggered only if the value of the dependent array changes

  • In addition, the old performance optimization logic of Redux remains, and if the current props are the same as the old props, the component will not be re-rendered.

  • Due to the batch update logic used in React Redux, multiple useselectors () in the same component recalculate state, causing the component to re-render only once. Therefore, we are free to useSelector() in components without worrying about repeated rendering

  • In the example below, we can split a single useSelector() into two independent ones (one reads title and the other reads content) useSelector() they are exactly the same in terms of performance and number of renders

import React from 'react';
import { useSelector } from 'react-redux';
 
const Component = props= > {
  const { title, content } = useSelector(state= > ({
      title: state.title, 
      content: state.content
  }));
  
  return <div title={title}>{content}</div>;
Copy the code
useDispatch
  • In addition to reading state in store, you can dispatch actions to update state in store. UseDispatch is one such API

  • This hook is what you need whenever a component needs to trigger a Redux action. Unfortunately, mapDispatchToProps is deprecated so whenever you want to dispatch an action, you need to use Dispatch (actionCreator()) to call its Action Creator

  • This is a bit of an awkward approach for us to use for the first time, since we used to call the Dispatch function wrapped as prop through Connect HOC

  • But the hooks approach brings more clarity to the code. Unfortunately, if we want to dispatch actions within an event handler, we must create an anonymous function such as :() => dispatch(actionCreator). Due to the nature of anonymous functions, this will get a new reference every time you re-render

  • If you pass this anonymous function to the child component as props, the child component will be rerendered each time. To optimize performance, the function must have the same reference, and the solution is to create this anonymous function in useCallback.

import { useDispatch } from 'react-redux'
import { logout } from '.. /store/reducer'
    const dispatch = useDispatch()
    / / logout
    const handleLogout = useCallback((a)= > {
        dispatch(logout())
    }, [dispatch])

Copy the code