The introduction

Hooks are designed to solve several problems with classComponents:

  • It is difficult to reuse logic (only HOC, or render props), resulting in a very hierarchical component tree
  • It creates huge components.
  • Class components are hard to understand, such as methods requiring bind and this pointing unambiguously

Also, to make FunctionalComponent have some of the features of ClassComponent.

Usage note:

  • You cannot put hooks in loops, conditional statements, or nested methods. React records the state in the order in which hooks appear.
  • Use hooks only in the Function component and custom hooks.
  • Naming conventions:
    • UseState returns the second item of the array beginning with set (by convention only).
    • Custom hooks start with use (verifiable by Lint).

Hooks provided in React:

  • UseState: setState
  • UseReducer: setState, and useState is also the wrapper for this method
  • useRef: ref
  • UseImperativeHandle: Assigns a specific attribute to a REF
  • UseContext: context, which must be used together with createContext
  • UseMemo: Can optimize setState
  • UseCallback: A variant of useMemo that optimizes the function
  • UseEffect: similar componentDidMount/Update, componentWillUnmount, when the effect of componentDidMount/Update, always at the end of the Update cycle (page rendering is finished) to perform
  • UseLayoutEffect: The same as useEffect, except that the callback is performed after the data is updated and before the page is rendered. This method blocks the page from rendering
  • UseDebugValue: The tag used to display custom hooks in the React developer tool

1.State Hooks

1.1 useState

const [state, setState] = useState(initialState)
Copy the code
  • UseState takes a single argument that can be passed as a value of any type or a function that returns a value of any type.
  • UseState returns an array whose first argument is the state we need to use, and whose second argument is a setter function that can pass variables of any type, or a function that accepts the old value of state and returns the new value of state.
function Counter({ initialCount }) {
  const [count, setCount] = useState(initialCount)
  // Lazy initialization
  const [state, setState] = useState((a)= > {
    const initialState = someExpensiveComputation(props)
 return initialState  })  return (  <>  Count: {count}  <button onClick={()= > setCount(0)}>Reset</button>  <button onClick={()= > setCount(prevCount => prevCount + 1)}>+</button>  <button onClick={()= > setCount(prevCount => prevCount - 1)}>-</button>  </>  ) } Copy the code

Note that the set method does not merge like setState of a class component, so it is recommended that:

  • If the data structure is simple, you can put the variables in different Usestates according to the data structure needs to avoid putting a lot of similar things into one object{... state, value}The situation.
  • If the data structure is complex, you are advised to use useReducer to manage the state of the component.

1.2 useReducer

const [state, dispatch] = useReducer(reducer, initialArg, init)
Copy the code
  • The useReducer accepts three arguments,The first parameter is a reducer function.The second parameter is the initial value from the Reducer.The third argument, which is optional, is a function that can be used to lazily provide the initial state. That means we can use oneinitFunction to calculate the initial state/value, rather than explicitly supplying the value. This is handy if the initial value might be different, and you end up with the calculated value instead of the initial value.
    • Reducer accepts two parameters, state and action. The usage principle is the same as reducer in REdux.
  • The useReducer returns an array containing a state and a Dispath. State is the value in the returned state, and dispatch is a function that can publish events to update state.

Note: React does not use the state = initialState convention popularized by Redux. Sometimes the initial value depends on props and therefore needs to be specified when the Hook is called. If you particularly like the above conventions, it is possible to mimic Redux behavior by calling useReducer(Reducer, undefined, reducer), but this is not encouraged.

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(a); } }  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: 'increment'})}>+</button> <button onClick={() => dispatch({type: 'decrement'})}>-</button> </> ); }  function render () {  ReactDOM.render(<Counter initialCount={0} />, document.getElementById('root')); } Copy the code

UseReucer is also an internal implementation of useState. UseState and useReucer are implemented by:

let memoizedState
function useReducer(reducer, initialArg, init) {
    let initState = void 0
    if (typeof init === 'function') {
        initState = init(initialArg)
 } else {  initState = initialArg  }  function dispatch(action) {  memoizedState = reducer(memoizedState, action)  // React render  // render()  }  memoizedState = memoizedState || initState  return [memoizedState, dispatch] }  function useState(initState) {  return useReducer((oldState, newState) = > {  if (typeof newState === 'function') {  return newState(oldState)  }  return newState  }, initState) } Copy the code

In some scenarios, useReducer is more suitable than useState. Kent C. Dodds provides a useReducer best practice: Use a useReducer when you have a state in one element that depends on a state in another element.

2.Effect Hooks

2.1 useEffect

useEffect(effect, array);
Copy the code

UseEffect takes two arguments and returns no value.

  • The first argument is the effect function, which fires at componentDidMmount and conditionally fires at componentDidUpdate (this is added as the second array argument to useEffect). The effect function can also return a function (returnFunction), ReturnFunction will fire at componentWillUnmount and conditionally before Effect at componentDidUpdate (returnFuncton before Effect, Such as need to do timer clearing). Note: Unlike componentDidMount and componentDidUpdate, the effect function fires after the browser has finished rendering. If you need to trigger before rendering, use useLayoutEffect.
  • The second parameter array is used as a conditional constraint in conditional trigger cases:
    • If not, every time componentDidUpdate returnFunction (if present) is raised, then Effect is raised.
    • If is an empty array[]ReturnFunction and effect are not triggered when componentDidUpdate.
    • If you only need to fire returnFunction and effect when you specify a variable change, put that variable into an array.

2.2 useLayoutEffect

useLayoutEffect(effect, array);
Copy the code

The useEffect method is the same as the useEffect method, but the timing of the callback is slightly different. The timing is more like componentDidMount and componentDidUpdate. Note, however, that this method is synchronous and is executed before Browser Paint, which prevents browser paint from doing anything with the DOM (such as sizing the DOM layout to prevent jitter).

UseEffect and useLayoutEffect

Normally, using the default useEffect hook is sufficient to ensure that state changes do not block the rendering process, but if an Effect update (cleanup) involves DOM updates, useEffect can have unexpected effects. This is the best time to use useLayoutEffect.

For example, requestAnimationFrame is a frame-by-frame animation. To make a useRaf hook, you need to use the latter to ensure that changes are synchronized. This is also in line with the author’s comment that the useEffect is very late, which can ensure that the page is stable before doing things.

The hook execution order is useLayoutEffect > requestAnimationFrame > useEffect

3.Context Hooks

To understand the API in Context Hooks, you first need to understand the Context and its usage scenarios.

Context is designed to share data that is considered “global” to a component tree.

Usage scenario: Context provides a way to pass data through the component tree, eliminating the need to manually pass props properties at each level.

Note: Do not use the context just to avoid passing props to components at several levels. It is used when multiple components at multiple levels need to access the same data.

3.1 createContext

const {Provider, Consumer} = React.createContext(defaultValue, calculateChangedBits)
Copy the code
  • This method creates a pair of {Provider, Consumer}. When React renders the Context component Consumer, it reads the current context value from the closest matching Provider in the upper part of the component tree. The Consumer is the Consumer of the data provided by the Provider.

  • If the upper component tree does not have a matching Provider and you need to render a Consumer component, you can use defaultValue. This helps to test components without encapsulating them. Such as:

    import React, { useContext} from 'react';
    import ReactDOM from 'react-dom';
    /* The result reads 123 because the Provider */ was not found
    const { Provider, Consumer } = React.createContext(123);
    function Bar() {
     return <Consumer>{color => <div>{color}</div>}</Consumer>; } function Foo() {  return <Bar />; } function App() {  return (  <Foo />  ); } ReactDOM.render(  <App />. document.getElementById('root') ) Copy the code

3.1.1 the Provider

The React component allows Consumers to subscribe to changes to the context. The Provider is the component that publishes this state, receiving a value attribute that is passed to the Provider’s descendants. A single Provider can relate to multiple Consumers. Providers can be nested to override deeper values in the component tree.

export const ProviderComponent = props= > {
  return (
    <Provider value={}>
      {props.children}
 </Provider>
 ) } Copy the code

The second argument in the createContext() function is calculateChangedBits, which is a function that takes newValue and oldValue and returns the value as changedBits. In the Provider, When changedBits = 0, updates are no longer triggered. In Consumer, there is an unstable prop, unstable_observedBits. If the Provider’s changedBits & observedBits = 0, the update will not be triggered.

const Context = React.createContext({foo: 0.bar: 0}, (a, b) => {
    let result = 0
    if(a.foo ! == b.foo) {        result |= 0b01
    }
 if(a.bar ! == b.bar) { result |= 0b10  }  return result }) Copy the code

3.1.2 Consumer

<Consumer>
  {value => /* render something based on the context value */}
</Consumer>
Copy the code
  • A React component that subscribes to context changes. When the context value changes, the Consumer value changes
  • Receives as a child a function that takes the value of the current context and returns a React node.The value passed to the function will be equal to the value property of the nearest Provider in the context above the component tree. If the context does not have a Provider, the value argument will be passed tocreateContext()DefaultValue.

Every time the value of the Provider changes, all Consumers that are descendants of the Provider are rerendered. The propagation of Consumers from the Provider to its descendants is not constrained by the shouldComponentUpdate method, so the descendant Consumer is updated even when the ancestor component exits the update.

// Create a theme Context. The default theme is light
const ThemeContext = React.createContext('light');

function ThemedButton(props) {
    The ThemedButton component receives the theme from the context
 return (  <ThemeContext.Consumer>  {theme => <Button {. props} theme={theme} />}  </ThemeContext.Consumer>  ) }  // Intermediate componentsfunction Toolbar(props) {  return (  <div>  <ThemedButton />  </div>  ) }  class App extends React.Component {  render() {  return (  <ThemeContext.Provider value="dark">  <Toolbar />  </ThemeContext.Provider>  )  } } Copy the code

3.2 useContext

const context = useContext(Context)
Copy the code

The effect is similar to that of Consumer, but it is functional and still needs to be used with Provider.

This function takes a Context parameter (the object that wraps the Provider and Consumer) and returns the value of the Provider property object.

const Context = React.createContext('light');

// Provider
class Provider extends Component {
  render() {
 return (  <Context.Provider value={'dark'} >  <DeepTree />  </Context.Provider>  )  } } Copy the code
// Consumer
function Consumer(props) {
  const context = useContext(Context)
  return (
    <div>  {context} // dark  </div>  ) } Copy the code

3.3 Used with useReducer

// Color.jsx
import React, { createContext, useReducer } from 'react'

export const ColorContext = createContext()
export const UPDATE_COLOR = 'UPDATE_COLOR'
 function reducer(state, action) {  switch (action.type) {  case UPDATE_COLOR:  return action.color  default:  return state  } }  export const Color = props= > {  const [color, dispatch] = useReducer(reducer, 'blue')  return (  <ColorContext.Provider value={{ color.dispatch}} >  {props.children}  </ColorContext.Provider>  ) } Copy the code
// Button.jsx
import React, { useContext } from 'react'
import { ColorContext, UPDATE_COLOR } from './Color'
function Buttons() {
  const { dispatch } = useContext(ColorContext)
 return (  <div>  <button  onClick={()= > {  dispatch({ type: UPDATE_COLOR, color: 'red' })  }}  >  red  </button>  <button  onClick={()= > {  dispatch({ type: UPDATE_COLOR, color: 'yellow' })  }}  >  yellow  </button>  </div>  ) }  export default Buttons Copy the code
// ShowArea.jsx
import React, { useContext } from 'react'
import { ColorContext } from './Color'
function ShowArea() {
  const { color } = useContext(ColorContext)
 return <div style={{ color}} >color:{color}</div> }  export default ShowArea Copy the code
// index.jsx
import React from 'react'
import ShowArea from './ShowArea'
import Buttons from './Buttons'
import { Color } from './Color'
function Demo() {  return (  <div>  <Color>  <ShowArea />  <Buttons />  </Color>  </div>  ) }  export default Demo Copy the code

4.Ref Hooks

4.1 useRef

const RefElement = createRef(initialValue)
Copy the code

4.1.1 Component References

UseRef may need to pass a parameter, which is usually used in another way for useRef. If it refers to an element object, it usually does not pass a parameter, and returns a mutable ref object with a current attribute pointing to the instance of the referenced object.

When it comes to useRef, we need to talk about createRef and why this API exists. (createRef uses the same method as useRef and returns a ref object.)

The effect of the two is basically the same when ref is used normally:

  • createRef

    import { React, createRef } from 'react'
    
    const FocusInput = (a)= > {
      const inputElement = createRef()
      const handleFocusInput = (a)= > {
     inputElement.current.focus()  }  return (  <>  <input type='text' ref={inputElement} />  <button onClick={handleFocusInput}>Focus Input</button>  </>  ) }  export default FocusInput Copy the code
  • useRef

    import { React, useRef } from 'react'
    
    const FocusInput = (a)= > {
      const inputElement = useRef()
      const handleFocusInput = (a)= > {
     inputElement.current.focus()  }  return (  <>  <input type='text' ref={inputElement} />  <button onClick={handleFocusInput}>Focus Input</button>  </>  ) }  export default FocusInput Copy the code

However, there is a fundamental difference between the ref and createRef references: createRef returns a new reference every time it renders, while useRef returns the same reference every time.

Like this:

const App = (a)= > {
  const [renderIndex, setRenderIndex] = React.useState(1)
  const refFromUseRef = React.useRef()
  const refFromCreateRef = createRef()

 if(! refFromUseRef.current) { refFromUseRef.current = renderIndex  }   if(! refFromCreateRef.current) { refFromCreateRef.current = renderIndex  }   return (  <>  <p>Current render index: {renderIndex}</p>  <p>  <b>refFromUseRef</b> value: {refFromUseRef.current}  </p>  <p>  <b>refFromCreateRef</b> value:{refFromCreateRef.current}  </p>   <button onClick={()= > setRenderIndex(prev => prev + 1)}>  Cause re-render  </button>  </>  ) } Copy the code
img

Because reffromuseref. current always exists, it does not change the value.

4.1.2 alternative to this

So why give useRef this feature, and in what circumstances do we need it?

A classic case:

import React, { useRef, useState } from 'react'

function App() {
  const [count, setCount] = useState()
  function handleAlertClick() {
 setTimeout((a)= > {  alert(`Yout clicked on ${count}`)  }, 3000)  }  return (  <div>  <p>You click {count} times</p>  <button onClick={()= > setCount(count + 1)}>Click me</button>  <button onClick={handleAlertClick}>Show alert</button>  </div>  ) }  export default App Copy the code
img

When we update the state, React will re-render the component, getting a separate count state each time, and re-render a handleAlertClick function. Each handleAlertClick has its own count inside it.

You will find that the value of count cannot display the updated data in real time. This is due to the closure mechanism existing in the value of JS. When clicking the popup button, the value of count has been determined and passed into the alert callback to form a closure. Subsequent value changes do not affect the triggering of the timer.

In a class component, if we use this.state.count, the result will be real-time because they all point to the same reference object.

In function components, we can use useRef to get new values in real time. This is another use of useRef, which is also equivalent to this and can hold any variable. UseRef is a great solution to the inconvenience of closures.

import React, { useRef, useState } from 'react'

function App() {
  const [count, setCount] = useState(0)
  const lastestCount = useRef()
 lastestCount.current = count  function handleAlertClick() {  setTimeout((a)= > {  alert(`You clicked on ${lastestCount.current}`) // Real-time results  }, 3000)  }  return (  <div>  <p>Yout click {count} times</p>  <button onClick={()= > setCount(count + 1)}>Click me</button>  <button onClick={handleAlertClick}>Show alert</button>  </div>  ) }  export default App Copy the code

It is important to note that if we pass a parameter in useRef, the result will be different if we use the following method to access the value:

import React, { useRef, useState } from 'react'

function App() {
  const [count, setCount] = useState(0)
  
 const lastestCount = useRef(count) // Pass count directly   function handleAlertClick() {  setTimeout((a)= > {  alert(`You clicked on ${lastestCount.current}`)  }, 3000)  }  return (  <div>  <p>Yout click {count} times</p>  <button onClick={()= > setCount(count + 1)}>Click me</button>  <button onClick={handleAlertClick}>Show alert</button>  </div>  ) }  export default App Copy the code

As we said, useRef always returns the same reference. The parameter was assigned to the current property when it was first passed in, and it returns an instance, and since it already has an instance, it simply returns the original instance. The parameters passed in are no longer in effect.

4.2 forwardRef

forwardRef((props, ref) = > {
    // dosomething
    return (
     <div ref={ref}></div>
    )
}) Copy the code

ForwardRef isn’t exactly in hooks, but if we’re going to use useImperativeHandle, we need to use it for collocation.

This method refers to the ref instance of the parent component as a parameter to the child component, which can be bound to the node of the child component itself.

This method can be thought of as a higher-order component, and its props takes only the children parameter. It passes ref and props from the parent to the child, which calls the ref passed by the parent.

The component that is passed in receives two parameters, the props passed by the parent component and a reference to ref.

// We can use a three-layer nesting of components and treat the function passed into the forwardRef as an intermediate layer for passing values
function InputWithLabel(props) {
  // myRef is the parent ref node driven externally
  const { label, myRef } = props
  const [value, setValue] = useState("")
 const handleChange = e= > {  const value = e.target.value  setValue(value)  }   return (  <div>  <span>{label}:</span>  <input type="text" ref={myRef} value={value} onChange={handleChange} />  </div>  ) }  // the parent forwardRef takes the parent ref node and passes it to the child as an argumentconst RefInput = React.forwardRef((props, ref) => ( <InputWithLabel {... props} myRef={ref} />))  // Call the RefInput procedurefunction App() { // Use useRef hook to get the corresponding ref node const myRef = useRef(null)   const handleFocus = () => {  const node = myRef.current  console.log(node)  node.focus()  }   return (  <div className="App"> <RefInput label={" name "} ref={myRef} /> <button onClick={handleFocus}>focus</button>  </div>  ) } Copy the code

4.3 useImperativeHandle

useImperativeHandle(ref, () => ({
    a:1.    b:2.    c:3
}))
Copy the code

UseImperativeHandle and forwardRef are recommended to be used together to reduce the exposure of parent components to properties and avoid imperative codes such as ref.

UseImperativeHandle takes three parameters:

  • The first argument receives a ref instance that references the parent through the forwardRef
  • The second argument is a callback function that returns an object containing properties or methods that need to be exposed to the parent component
  • The third argument is an optional argument that is an array of dependencies, like useEffect
function Example(props, ref) {
    const inputRef = useRef()
    useImperativeHandle(ref, () => ({
        The parent component can use the focus method passed by the child component via this.xxx.current. Focus
        focus: (a)= > {
 inputRef.current.focus()  }  }))  return <input ref={inputRef} /> }  export default forwardRef(Example) Copy the code
class App extends Component {
  constructor(props){
      super(props)
      this.inputRef = createRef()
  }
  render() {  return (  <>  <Example ref={this.inputRef}/>  <button onClick={() => {this.inputRef.current.focus()}}>Click</button>  </>  )  } } Copy the code

5. Performance optimization

5.1 memo

MemoComponent = memo(Component)
Copy the code

As we all know, for class components, there is a PureComponent that can optimize rendering performance by determining whether the props passed by the parent component have changed. React also has a higher-order component, Memo, that functions like PureComponent. The memo is used to determine whether the props passed by the parent component have changed to render the current component.

How to use it is simple:

import React, { memo } from 'react'

function Demo(props){
    return (
     <div>{props.name}</div>
 ) }  export default memo(Demo) Copy the code

5.2 useMemo

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

UseMemo is a react-implemented hooks for optimizing the performance of functional components. It can pass in two parameters:

  • The first argument is a factory function that returns a cached value, meaning that the callback recalculates the cached data only if the value in the array changes during rerendering, which saves us from having to do a complex calculation of the data every time we rerender.
  • The second argument is an array of dependencies that are recalculated only if the data in the dependency changes, the same as the useEffect array of dependencies
import React, { useState, useMemo } from 'react'

function Child({ color }) {
 // If the color value does not change, console will not be printed, but rerender will still be triggered. If this function is not executed, add the memo to the outermost layer
    const actionColor = useMemo((a)= > {
 console.log('color update')  return color  }, [color])   return <div style={{ actionColor}} >{actionColor}</div> }  function MemoCount() {  const [count, setCount] = useState(0)  const [color, setColor] = useState('blue')  return (  <div>  <button  onClick={()= > {  setCount(count + 1)  }}  >  Update Count  </button>  <button  onClick={()= > {  setColor('green')  }}  >  Update Color  </button>  <div>{count}</div>  <Child color={color} />  </div>  ) }  export default MemoCount Copy the code

The example above is not the most commonly used scenario for useMemo. As mentioned earlier, the Memo component will only be re-rendered if the props object is changed, but if the actual value is not changed, the component will still be re-rendered. Like this:

import React, { useState, memo } from 'react'

const Child = memo(({ config }) = > {
    console.log(config)
    return <div style={{ color:config.color}} >{config.text}</div>
})  function MemoCount() {  const [count, setCount] = useState(0)  const [color, setColor] = useState('blue')  const config = {  color,  text:color  }  return (  <div>  <button  onClick={()= > {  setCount(count + 1)  }}  >  Update Count  </button>  <button  onClick={()= > {  setColor('green')  }}  >  Update Color  </button>  <div>{count}</div>  <Child config={config} />  </div>  ) }  export default MemoCount Copy the code

When we change the count value, we find that it has nothing to do with the config object, but the Child component is still rerendered because the parent component rerenders the config object. The value in the new object is the same, but because it is a reference object, So it still changes, and to change that, we need:

/ / use useMemo
import React, { useState,useMemo, memo } from 'react'

const Child = memo(({ config }) = > {
  console.log(config)
 return <div style={{ color:config.color}} >{config.text}</div> })  function MemoCount() {  const [count, setCount] = useState(0)  const [color, setColor] = useState('blue')  // Only different objects will be returned depending on the color change, otherwise the same reference object will be returned  const config = useMemo((a)= >({  color,  text:color  }),[color])   return (  <div>  <button  onClick={()= > {  setCount(count + 1)  }}  >  Update Count  </button>  <button  onClick={()= > {  setColor('green')  }}  >  Update Color  </button>  <div>{count}</div>  <Child config={config} />  </div>  ) }  export default MemoCount Copy the code

This way, when the value of count changes, the child component will not be re-rendered.

5.3 useCallback

const memoizedCallback = useCallback(
  (a)= > {
    doSomething(a, b)
  },
  [a, b],
) Copy the code

The use of useCallback is similar to that of useMemo, which is specifically used to cache hooks that receive two arguments. The first argument we pass in is the callback function that we want to cache.

Note: The second parameter is currently only used to specify parameters that need to be checked for change and is not passed as a parameter to the callback function. It is recommended that all variables used in callback functions be listed in arrays.

To pass arguments to the callback function, we can use the higher-order function method. UseCallback will cache the higher-order function for us, as shown above.

Of course, we can also write parameters in callback:

const memoizedCallback = useCallback(
  (a, b) = > {
    doSomething(a, b)
  },
[].) // memoizedCallback is the callback function passed in Copy the code

As you can see, the callback function is triggered when the dependency mode changes. UseCallback (FN, inputs) equals useMemo(() => FN, inputs)

// How to implement useCallback
let memoizedState = null
function useCallback(callback, inputs) {
  const nextInputs =
inputs ! = =undefined&& inputs ! = =null ? inputs : [callback]
 const prevState = memoizedState;  if(prevState ! = =null) {  const prevInputs = prevState[1]  if (areHookInputsEqual(nextInputs, prevInputs)) {  return prevState[0]  }  }  memoizedState = [callback, nextInputs]  return callback }  // The useMemo implementation principle function useMemo(callback, inputs){  return useCallback(callbak(),inputs) } Copy the code

More specifically, useCallback is used when binding functions to events in React and passing in parameters:

// The following situation ensures that the component re-renders the same object as the method, avoiding passing a different function reference each time it passes onClick
import React, { useState, useCallback } from 'react'

function MemoCount() {
    const [count, setCount] = useState(0)
  memoSetCount = useCallback((a)= >{  setCount(count + 1) }, [])  return (  <div>  <button  onClick={memoSetCount}  >  Update Count  </button>  <div>{color}</div>  </div>  ) }  export default MemoCount Copy the code

6.Debug

6.1 useDebugValue

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

UseDebugValue can be used to display tags for custom hooks in the React developer tool.

UseDebugValue receives two parameters, which can be used in different ways according to the number of parameters passed in:

  • Directly upload the debug value

    function useFriendStatus(friendID) {
      const [isOnline, setIsOnline] = useState(null);
    
      // ...
    
     // Display the label next to the Hook in the developer tools  // e.g. "FriendStatus: Online"  useDebugValue(isOnline ? 'Online' : 'Offline');   return isOnline; } Copy the code
  • Delay formatting debug values

    const date = new Date(a)useDebugValue(date, date => date.toDateString())
    Copy the code

7. Customize Hooks

A custom Hook is a function whose name isuseAt the beginning, other hooks can be called inside the function

// myhooks.js
// Below we define a custom hooks to get window width and length values
import React, { useState, useEffect, useCallback } from 'react'

function useWinSize() {
 const [size, setSize] = useState({  width: document.documentElement.clientWidth,  height: document.documentElement.clientHeight  })  const onResize = useCallback((a)= > {  setSize({  width: document.documentElement.clientWidth,  height: document.documentElement.clientHeight  })  }, [])   useEffect((a)= > {  window.addEventListener('resize', onResize)  return (a)= > {  window.removeEventListener('reisze', onResize)  }  }, [onResize])  return size }  export const useWinSize Copy the code
import { useWinSize } from './myhooks'
function MyHooksComponent() {
  const size = useWinSize()
  return (
    <div> Page Size: {Size. Width} {x the Size, height} </div>  ) }  export default MyHooksComponent Copy the code

reference

  • You don’t know useRef
  • React Hooks Tutorial – Ruan Yifeng
  • React Hooks official documentation

This article is formatted using MDNICE