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.

What is a Hook?

A Hook is a function that lets you “Hook” features like React state and lifecycle into a function component. Hooks cannot be used in class components — this allows you to use React without using class. \

React has hooks like useState built in. You can also create your own hooks to duplicate the state logic between different components.

Rules of the Hook

  • Never call hooks in loops, conditions, or nested functions. Make sure you always call them at the top of your React function.
  • Do not call a Hook in a normal JavaScript function.

useState

The following example demonstrates the use of useState. When you click the button, the counter increases in value:

import React, { useState } from 'react'; Function Example() {// Declare a 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

UseState is a Hook. Add some internal state to the component by calling it from within the function component. React will retain this state for repeated rendering. 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. It is similar to the this.setState of the class component, but it does not merge the new state with the old state. \

The only argument to useState is the initial state. In the example above, our counter starts at zero, so the initial state is 0. Note that, unlike this.state, state doesn’t have to be an object — it can be of any type if you need it. The initial state parameter is only used for the first rendering.

Declare multiple state variables

You can use State Hook multiple times in a component:

Const MyStates() {// Declare multiple state variables! const [age, setAge] = useState(42); const [fruit, setFruit] = useState('banana'); const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]); / /... }Copy the code

An array of deconstruction

The syntax of array deconstruction allows us to give the state variable a different name when calling useState. Of course, these names are not part of the useState API. Array deconstruction:

    const [a, b] = [1.() = > {}];
    console.log(a, b); // 1 () => {}
Copy the code

UseState returns an array, the 0th item current state, and the first item updates its function.

UseState update function setxxx

It takes any type or a callback function

function Counter() { const [count, setCount] = useState(0); UseEffect (() => {setCount(c => c + 1); // call setCount(2); // Accept any type}, []); return <h1>{count}</h1>; }Copy the code

useEffect

The React component performs data fetching, subscriptions, or manual DOM modification. We collectively refer to these operations as “side effects.” Effect Hook, which gives function components the ability to manipulate side effects. It goes with the class in the component componentDidMount, componentDidUpdate and componentWillUnmount have the same purpose, just merge into an API.

import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); ComponentDidMount and componentDidUpdate: Document. title = 'You clicked ${count} times'; useEffect() => {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

When you call useEffect, you’re telling React to run your “side effect” function after making changes to the DOM. Because side functions are declared inside the component, they can access the props and state of the component. By default, React calls the side effect function after every render, i.e. useEffect is called on every render.

Remove useEffect

Side effects functions can also specify how to “clear” side effects by returning a function. For example, use the side effects function in the following component to subscribe to a friend’s online status and clear it by unsubscribing:

import React, { useState, useEffect } from 'react'; function FriendStatus(props) { const [isOnline, setIsOnline] = useState(null); function handleStatusChange(status) { setIsOnline(status.isOnline); } useEffect(() => { ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; }); if (isOnline === null) { return 'Loading... '; } return isOnline ? 'Online' : 'Offline'; }Copy the code

UseEffect multiple times

Like useState, you can use useEffect multiple times in a component:

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

  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }
  // ...
Copy the code

UseEffect Second argument (performance optimization by skipping Effect)

In some cases, performing cleanup or effect after every render can cause performance problems. In the Class component, we can resolve this by adding the prevProps or prevState comparison logic to componentDidUpdate: prevProps

componentDidUpdate(prevProps, prevState) {
  if (prevState.count !== this.state.count) {
    document.title = `You clicked ${this.state.count} times`;
  }
}
Copy the code

This is a common requirement, so it is built into the Hook API for useEffect. If certain values don’t change between rerenderers, you can tell React to skip the effect call by passing the array as the second optional argument to useEffect:

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

When count changes, React calls effect again. React executes effect if there are multiple elements in the array, even if only one element changes.

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. Remember that the useContext argument must be the context object itself (the object created by react.createcontext ()).

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() { const theme = useContext(ThemeContext); return ( <button style={{ background: theme.background, color: theme.foreground }}> I am styled by theme context! </button> ); }Copy the code

React. CreateContext accepts an initial value by default.

useReducer

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

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

UseReducer can be more useful than useState in some situations, such as when the state logic is complex and contains multiple subvalues, or when the next state depends on the previous state. Also, using useReducer can optimize performance for components that trigger deep updates because you can pass dispatches to child components instead of callbacks.

There are two different ways to initialize useReducer state. You can choose one of them based on your application scenario. It is easiest to pass the initial state as the second argument to the useReducer:

const [state, dispatch] = useReducer(
    reducer,
    {count: initialCount}  );
Copy the code

Lazy initialization You can optionally create the initial state lazily. To do this, you need to pass in the init function as the third argument to the useReducer, so that the initial state will be set to init(initialArg).

Doing so extracts the logic used to calculate state outside the Reducer, which also facilitates future actions to reset state:

function init(initialCount) { return {count: initialCount}; } function reducer(state, action) { switch (action.type) { case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; case 'reset': return init(action.payload); default: throw new Error(); } } function Counter({initialCount}) { const [state, dispatch] = useReducer(reducer, initialCount, init); return ( <> Count: {state.count} <button onClick={() => dispatch({type: 'reset', payload: initialCount})}> Reset </button> <button onClick={() => dispatch({type: 'decrement'})}>-</button> <button onClick={() => dispatch({type: 'increment'})}>+</button> </> ); }Copy the code

Tip: If the Reducer Hook returns the same value as the current state, React skips the rendering of the child components and the execution of the side effects.

useRef

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. A common use case is to mandate access to child components:

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

In essence, useRef is like a “box” that can hold a mutable value in its.current property. \

Remember that useRef does not notify you when the ref object contents change. Changing the.current property does not cause component rerendering. If you want to run some code when React binds or unbinds the REF of the DOM node, you need to use the ref callback to do so.

Other hook

  • useCallback
  • useMemo
  • useImperativeHandle
  • useLayoutEffect
  • useDebugValue

reference

react