This article is only part of the official website materials for personal use, you can directly read React Hook official website introduction, do not read here.

Why do you need Hooks

  1. It is difficult to reuse state logic between components
  2. Complex components become difficult to understand (doing various things in lifecycle functions)
  3. Unintelligible class

Using useState

How to use

[state variable, change function] = useState(initial value)

How to record values

  1. The “location” of values in the order in which the useState appears
  2. Every time[state variable, change function] = useState(initial value)Call, create a space within the closure, and do the index extraction in order
  3. Based on the second point, useState must be written in the outermost layer of the function to avoid nested if/else logic

Using useEffect

Pay attention to

UseEffect Runtime time Is similar to componentDidMount, componentDidUpdate, and componentWillUnmount. It is called only after Dom updates are performed

How to use

useEffect(() => {
  // do something
  document.title = `You clicked ${count} times`;
})
Copy the code

How to remove

useEffect(() => { // do something ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); / / by returning a callback function to cancel the return () = > {ChatAPI. UnsubscribeFromFriendStatus (props. Friend. Id, handleStatusChange); }})Copy the code

Skip some unnecessary side effects

useEffect((a)= > {
  document.title = `You clicked ${count} times`;
  // The 'document.title' sentence will be reexecuted only if the count value changes
  // Do not pass an empty array, there may be other problems
}, [count]);
Copy the code

The rules

  1. Hooks can only be called on the outermost layer of a function. Do not call inside a loop, condition, or subfunction
  2. Hooks can only be called in React function components. Do not call it in another JavaScript function. (There’s another place to call a Hook — in your own custom Hook, which we’ll learn about later.)

eslint-plugin-react-hooks

Each time the State Hook function is called, it is a new State. Each time an Effect Hook is called, a new function is executed again, and each Effect “belongs” to a specific render.

Custom Effect Hooks

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

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

    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}
Copy the code

Hook API index

Based on the hooks

useState

slightly

useEffect

slightly

useContext

const themes = { light: { foreground: "#000000", background: "#eeeeee" }, dark: { foreground: "#ffffff", background: "# 222222"}}; const ThemeContext = React.createContext(themes.light); function App() { return ( <ThemeContext.Provider value={themes.dark}> <Toolbar /> </ThemeContext.Provider> ); } function Toolbar(props) { return ( <div> <ThemedButton /> </div> ); } function ThemedButton() {// useContext(MyContext) = static contextType = MyContext or <MyContext.Consumer> const theme = useContext(ThemeContext); return ( <button style={{ background: theme.background, color: theme.foreground }}> I am styled by theme context! </button> ); }Copy the code

Additional hooks

useReducer

const [state, dispatch] = useReducer(reducer, initialArg, init);
Copy the code

useCallback

It is useful when passing callback functions to child components that are optimized and use reference equality to avoid non-essential rendering (such as shouldComponentUpdate)

UseMemo (() => fn, deps)

// doSomething is executed only when a, b change
const memoizedCallback = useCallback(
  (a)= > {
    doSomething(a, b);
  },
  [a, b],
);
Copy the code

useMemo

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

You can use useMemo as a performance optimization tool, but don’t use it as a semantic guarantee. In the future, React may choose to “forget” some of the previous memoized values and recalculate them on the next render, such as freeing up memory for off-screen components. Write code that can execute without useMemo first — then add useMemo to your code to optimize performance.

Short message: don’t use it until you need it later

useRef

const refContainer = useRef(initialValue); function TextInputWithFocusButton() { const inputEl = useRef(null); Const onButtonClick = () => {// 'current' points to the text input element mounted to the DOM inputel.current.focus (); }; return ( <> <input ref={inputEl} type="text" /> <button onClick={onButtonClick}>Focus the input</button> </> ); }Copy the code

useImperativeHandle

This allows you to customize the instance value exposed to the parent component when using the REF

useImperativeHandle(ref, createHandle, [deps])

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

useLayoutEffect

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

Use standard useEffect whenever possible to avoid blocking visual updates.

It is recommended that you start with useEffect and only try useLayoutEffect if it fails

useDebugValue

The tag used to display custom hooks in the React developer tools

function useFriendStatus(friendID) { const [isOnline, setIsOnline] = useState(null); / /... // e.g. "FriendStatus: Online" useDebugValue(isOnline? 'Online' : 'Offline'); return isOnline; }Copy the code

FAQ

How do I use hooks for data retrieval?

The requested FETCH is placed in the useEffect callback function

How do I get props or state from the last round?

function Counter() {
  const [count, setCount] = useState(0);
  const prevCount = usePrevious(count);
  return <h1>Now: {count}, before: {prevCount}</h1>;
}

function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}
Copy the code

How do I measure DOM nodes?

You can use callback ref

function MeasureExample() { const [height, setHeight] = useState(0); const measuredRef = useCallback(node => { if (node ! == null) { setHeight(node.getBoundingClientRect().height); }} []); return ( <> <h1 ref={measuredRef}>Hello, world</h1> <h2>The above header is {Math.round(height)}px tall</h2> </> ); }Copy the code

In this case, we chose not to use useRef because it does not notify us of changes in the current ref value when ref is an object. Using callback Ref ensures that even if the child component delays displaying the measured node (for example, in response to a click), we can still receive the relevant information in the parent component to update the measurement results.

Notice that we passed [] as a list of dependencies for the useCallback. This ensures that the ref Callback does not change when it is rendered again, so React does not call it when it is not necessary.

Abstract encapsulation

function useClientRect() { const [rect, setRect] = useState(null); const ref = useCallback(node => { if (node ! == null) { setRect(node.getBoundingClientRect()); }} []); return [rect, ref]; }Copy the code