Learn from react-hooks

And welcome to visit my blog

react hooksclass ComponentThe difference between

  • It is written more succinct, eliminating the need to write long life cycle functions
  • class Componet hocIt is difficult to reuse state logic between components.

hooksUse rules

  • A Hook can only be called on the outermost layer of a function. Do not call in loops, conditional judgments, or subfunctions.
  • You can only call a Hook in the React function component. Do not call it from another JavaScript function. In addition to custom hooks

react hooksCommon API usage

useStateusage

identity: const [state, setState] = useState(initialState)

UseState adds a state hook to the React function component.

import React, { useState } from 'react'; function Count() { /* - count <=> this.state.count, SetCount (count + 1) or setCount(preState => preState + 1) setCount(preState => preState + 1) Merges setcounts in a short period of time into a single method. The second method does not use the merge mechanism of the first method. */ const [count, setCount] = useState(0); return <div onClick={setCount(pre => pre + 1)}>{count}</div> }Copy the code

useEffectusage

identity: useEffect(callBack:clearCallBack, [deps])

UseEffect is used to perform side effects on ComponetDidMount, ComponentDidUpdate, ComponentWillUnmount. UseEffect is used to perform side effects on ComponetDidMount, ComponentDidUpdate, ComponentWillUnmount.

import React, { useState, useEffect } from 'react'; Function Example() {/* -useeffect Takes a callBack argument as a dependency on the values in the array. If the values in the array change, callBack will be called again. Equivalent to ComponentDidupDate-Callback returns a clearCallBack, which is called when the component is uninstalled. This is equivalent to ComponentWillUnmount - useEffect calling callBack by default after the render process is complete. Const [isonline, setIsOnline] = useState(false); const [isonline, setIsOnline] = useState(false); useEffect(() => { ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange) return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange) } }, [isonline]) }Copy the code

useContextusage

UseContext takes a context object and returns the current value of that context. Mainly used for deep level component communication. The value of context that needs to be used with React. CreateContext is determined by the

value prop of the upper-layer component closest to the current component. In addition, updating the value of the value causes the component that called the uesContext to be re-rendered.

Note that components that call useContext are rerendered even if they are declared using react. memo. Therefore, memoization is required for optimization.

import React, { createContext, Children, useContext, useMemo } from 'react' const GlobalContext = React.createContext() function Child() { const data = Return useMemo(() => {return <div>{data.name}</div>}, [data.name]) } function Parent() { return ( <div> <p>Parent</p> <GlobalContext.Provider value={{name: 'woyao'}}> <Child /> </GlobalContext.Provider> </div> ) }Copy the code

useRefusage

UseRef returns a mutable ref object. Ref.current is a global constant within the component. This is equivalent to writing a global constant outside the component. That is, every time a function component is rerendered, the ref object is the same. Used to access the Dom as a global variable.

Access to the Dom

    import React, { useRef } from 'react'
    function Example() {
        const inputElement = useRef(null)
        const btnClick = (event) => {
            inputElement.current.focus()
        }
        return (
            <React.Fragment>
                <input ref={inputElement} />
                <button ref={btn} onClick={btnClick}/>
            </React.Fragment>
        )
    }

Copy the code

As a global variable

Import React, {useRef, useEffect, useState} from 'React' function usePrevious(value) { UseRef, const ref = useRef() /* Each time reRender is re-executed - it returns what value was before the last rendering - note that return is executed first, In the execution useEffect * / useEffect (() = > {ref. Current = value}) return ref. () function Counter current} {const [count, setCount] = useState(0) const preCount = usePrevious(count) return ( <div> <p>previous: {preCount} </p> <p>now: {count}</p> <button onClick={() => setCount(count + 1)}>click</button> </div> ) }Copy the code

useImperativeHandleusage

identity: useImperativeHandle(ref, createHandle, [deps])

UseImperativeHandle lets you customize the instance value exposed to the parent component when using the ref, in conjunction with the forwardRef. A method that lets you call a child from a parent component.

import React, { useRef, useImperativeHandle, forwardRef } from 'react' function MyInput(props, Const inputRef = useRef() const childFunc = () => {console.log('hh')} /* ref: ref createHandle: */ useImperativeHandle(ref, () => ({focus: () => { inputRef.current.focus() }, childFunc })) return <input ref={inputRef} /> } MyInput = forwardRef(MyInput) function App() { const myInputCoponent = useRef() return ( <> <MyInput ref={myInputCoponent} /> <button onClick={() => { myInputCoponent.current.childFunc() }}> focus now </button> </> ) }Copy the code

useReducerusage

identity: const [state, dispatch] = useReducer(reducer, initialArg, init)

UseReducer, an alternative to useState, accepts a Reducer of the form (state, action) => newState and returns the current state and its accompanying dispatch methods.

    const initialState = {count: 0};

    function reducer(state, action) {
        switch (action.type) {
            case 'increment':
                return {count: state.count + 1};
            case 'decrement':
                return {count: state.count - 1};
            default:
                throw new Error();
        }
    }

    function Counter() {
        const [state, dispatch] = useReducer(reducer, initialState);
        return (
            <>
                Count: {state.count}
                <button onClick={() => dispatch({type: 'decrement'})}>-</button>
                <button onClick={() => dispatch({type: 'increment'})}>+</button>
            </>
        );
    }
Copy the code

useMemousage

identity: const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]) newRenderTemplate = useMemo(() => renderTemplate(), [deps])

UseMemo is a hook to reduce component rendering times and optimize component performance. The functions passed into useMemo will be executed during rendering, please do not perform any operations unrelated to rendering inside the function, in fact, new memoizedValue will be generated only when the dependency changes. This reduces unnecessary rendering. It is usually used to decouple components, so that the logic related to this logical rendering is re-rendered if it changes, and the unrelated logic is not re-rendered. In plain English, there is a render associated with count logic and a render associated with name logic. Do not re-execute the count rendering function because the state property of name changes.

import React, { useState, useMemo } from 'react' const log = console.log.bind(console) function Child(props) { log('child render') const [count, SetCount] = useState(0) const renderCountTemplate = (count) => { console.log('count render') return <div>{count}</div> } Return (<div> child, {props. Name} {/* - useMemo prevents unnecessary render updates, and does not re-execute renderCountTemplate because of changes to the props of the current parent component. } {useMemo(() => renderCountTemplate(count), [count])} </div>)} // Child Prevents updates to the parent component, Child = react.memo (Child) function App() {log('parent render') const [name, SetName] = useState('') return ( <> <div>parent, {name}</div> <input onChange={(event) => SetName(event.target.value)} /> <Child name={name} /> </> ) }Copy the code

useCallbackusage

identity: const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b]);

UseCallback is a hook to reduce component rendering times and optimize component performance, similar to useMemo. Callbacks update the usual handling of anonymous functions in event functions only when a dependency changes. Of course, where you can use useMemo, you can also use useCallback.

import React, { useCallback, useState } from 'react' const [ count, setCount ] = useState(0) function Counter() { <! -- prevents rerendering every time count changes, Return <div onClick={useCallback(() => useCallback(() => setCount(count+1), [])}>{count}</div> }Copy the code

useLayoutEffectusage

UseLayoutEffect calls effect synchronously after all DOM changes. UseEffect calls effect asynchronously after all DOM changes.

  • You can use it to read DOM layouts and trigger rerenders synchronously
  • Before the browser executes the drawing,useLayoutEffectInternal update schedules will be refreshed synchronously.
  • Let’s just say I’m not toouseLayoutEffectThe difference between. The following code can be used for reference. Estimated in useuseEffectWhen brought page jitter problem when useduseLayoutEffect. Layout is synchronized as soon as the component tree is built or refreshed. Effect will wait until the rest of the JS code has finished executing
function App() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    if (count === 0) {
      const randomNum = 10 + Math.random()*200
      setCount(10 + Math.random()*200);
    }
  }, [count]);

  return (
      <div onClick={() => setCount(0)}>{count}</div>
  );
}
Copy the code

The effect is as follows:

function App() {
  const [count, setCount] = useState(0);

  useLayoutEffect(() => {
    if (count === 0) {
      const randomNum = 10 + Math.random()*200
      setCount(10 + Math.random()*200);
    }
  }, [count]);

  return (
      <div onClick={() => setCount(0)}>{count}</div>
  );
}
Copy the code

The effect is as follows:

Customize the hook

  • useDidUpdate
  • useGlobalReduxHook
Import {useEffect, useRef} from 'react' function useDidUpdate(cb, useDidUpdate) deps=[]) { const didMount = useRef(false) useEffect(() => { if (! didMount.current) { didMount.current = true return } cb() }, deps) return didMount.current }Copy the code
Import React, {useContext, useReducer} from 'React' const initState = {count: 0 } const Store = React.createContext(initStore) const MapActionReducer = { ['ADD'](state, action) { return {... state, count: action.payload} } } const reducer = (initState, action) => { return MapActionReducer[action.type](initState, } function useGlobalReduxHook(Component) {// dispatch state changes, Const [state, dispatch] = useReducer(reducer, Store) return (< store. Provider value={state, dispatch} /> <Component /> </Store.Provider> ) }Copy the code