This article will focus on the specific use of the Hook API. The principle will be explained in subsequent articles.

useState

We start with a Hook to declare a state, which is an API we need for everything we do.

import React, { useState } from 'react'; State const [count, setCount] = useState(0)} function Example() {// Declare a state const [count, setCount] = useState(0)}Copy the code

What do YOU do when you call the useState method?

It defines a state variable for us, and this variable is called count, you can call it anything. Normally, variables “disappear” after functions are pushed out, while variables in state are retained by React.

What parameters does useState require?

You only need one parameter, which will be the default value of count. We can pass numbers, strings, objects, etc. It depends on your personal needs. Call useState one more time if you want to create two variables.

What is the return value of useState?

The current state is returned, along with a function that modifies state. The setCount function will only modify count, so be careful to avoid naming conflicts.

How do I read/update state?

We want to use our state in the DOM and display it on the page:

import React, { useState } from 'react'; Function Example() {// declare a state const [count, setCount] = useState(0) return (<div> { count }</div> ) }Copy the code

We want to update the page state to be data-responsive:

import React, { useState } from 'react'; Function Example() {// declare a state const [count, SetCount] = useState(0) const fn = () => {setCount(count + 1)} return (<div> { count }</div> <button onClick={() => fn()}></button> ) }Copy the code

useEffect

There are two common side effects operations in the React component, those that need to be cleaned and those that do not.

Effect that does not need to be cleaned

Sometimes we just want to run some extra code after React updates the DOM. Such as sending network requests, logging, etc., these are common operations that do not require requests. Because we can ignore them after we’ve done these operations.

Take a look at the following code:

import React, { useState, useEffect } from 'react';
function Example() {
  const [count, setCount] = useState(0);

  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

What does the useEffect do?

This Hook will do what you want to do after rendering.

React saves the function you pass in internally and calls it (called effect) after a DOM update.

Why is uesEffect called inside a component?

Put it inside the component to directly access the count variable, or other props.

Hooks use JavaScript’s closure mechanism.

Will useEffect be executed after every render?

By default, React ensures that the DOM is updated every time the effect function is run.

He can control it.

Pay attention to

  • Each time you re-render, a new effect is generated, replacing the previous effect.
  • Unlike componentDidMount or componentDidUpdate, useEffect does not block the browser update screen.

Effects that need to be cleared

For example, if you subscribe to an external data source, it is important to clear effects in order to prevent memory leaks.

Consider the following example:

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

If your effect returns a function, React will call it when the cleanup operation is performed.

Why return a function in effect?

The idea is that both parts of the code act on the same side effect, and that they are part of effect, rather than being split apart.

React when to remove an effect?

It will perform the cleanup operation when the component is uninstalled.

He clears the previous effect before calling the new one. For example, if the first effect is called, the cleared effect will be stored, and the first effect will be cleared the second time.

Optimize performance by skipping Effect

In some cases, executing effect after every render can cause performance problems.

If certain values do not change between rerenders, execution of the effect function can be skipped. Here’s an example:

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

The second argument does this; if the count in [count] does not change, effect is not executed.

If you only want to execute effect once, pass an empty array.

useContext

This Hook needs to be used with other methods, for example:

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

First a context object is returned by React. CreateContext.

Our component is wrapped with themecontext.provider, for example: < themecontext. Provider value={themes.dark}> our component
so that the value is passed down. Any child component, however deep, will receive the value passed by value.

The underlying child can receive a value from the outer layer using useContext(ThemeContext), and useContext will return that value.

advantages

  • No more props for passing.
  • It’s not going to be like props going layer by layer.
  • State management becomes easier. Even for sibling components, the same state can be modified through object methods.

useReducer

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

Three parameters:

  • Reducer: Execute the function.
  • InitialArg: default value.
  • Init: lazily initializes data.

In case you don’t understand what lazy initialization data is, let me look at this example:

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

The Counter function and will take an argument that will be passed to the init function via the useReducer and will be used as the default value for state.

When dispatch is called, one parameter is passed as the reducer action and the return value of the init function as the reducer state.

Is it too confusing? IO /s/relaxed-b… codesandbox.io/s/relaxed-b…

Skip the dispatch

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

React internally uses the Object.is comparison algorithm to compare states.

useCallback

Two parameters to useCallback:

  • Function that is called when the second argument to listen on changes
  • Array, listens for changes in the value of the array, and executes only once if the array is empty.

Return value of useCallback:

  • Return us a function.

Look at the following example

import "./styles.css"; import React, { useCallback, useState } from "react"; export default function App() { const [a, setA] = useState(0); const [b, setB] = useState(0); const memoizedCallback = useCallback(() => { console.log(a, b); setA(a + 1); setB(b + 1); }, [a, b]); return ( <div className="App"> <h1>Hello CodeSandbox</h1> <h2>Start editing to see some magic happen! </h2> {a}----{b} <button onClick={() => memoizedCallback()}>click</button> </div> ) }Copy the code

When the click button is clicked, the function memoizedCallback returned by useCallback is called to the function of the first argument to useCallback.

useMemo

Two parameters of useMemo:

  • Function that is called when the dependency array has changed
  • The dependency array, if not provided, will be evaluated each time it is rendered.

UseMemo return value:

  • It returns value, which is different from useCallback.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b])
Copy the code

Recalculation occurs only when a dependency changes. This avoids costly calculations every time you render.

useRef

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

UseRef returns a mutable Ref object, and the.current property is initialized as the parameter passed in.

When the.current property changes, it does not cause the component to be rerendered.

useLayoutEffect

The function signature is the same as useEffect, which is called synchronously after all your DOM changes.

You can use it to read the DOM layout and trigger rerendering synchronously.

UseLayoutEffect is an internal update plan that is refreshed synchronously before the browser draws.

useImperativeHandle

It allows the child component to control which values do not need to be exposed to the parent component when using the REF.

It should be used with forwardRef.

Look at this example:

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

FancyInput will become a

component, and the parent component can only call the inputref.current. Focus () method exposed in the focus function.

useDebugValue

It displays custom Hook tags in the React development tool.

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

You can take as a second argument a formatting function that will only be called if the Hook is checked. It accepts the debug value as an argument and returns a formatted display value.

useDebugValue(date, date => date.toDateString());
Copy the code

For example, in the example above, a custom Hook that returns a date value can be formatted to avoid unnecessary toDtaeString calls.

conclusion

  • Based on the hooks

    • useState
    • useEffect
    • useContext
  • Additional hooks

    • useReducer
    • useCallback
    • useMemo
    • useRef
    • useImperativeHandle
    • useLayoutEffect
    • useDebugValue