I Love ReactJS

Understand these 12 Hooks and make sure you can play React (2)

play React Hooks

in the above, we talked about using useMemo to handle extraneous rendering. Next, let's take a look at the magic use of these hooks of React Hooks (it is recommended to be familiar with and use the corresponding React Hooks before you can make a good hook)

useMemo

when a child component is called in a parent component, the state of the parent component changes, causing the parent component to update, while the child component is updated even though it has not changed.

to put it simply, when the content of a page is very complex and there are many modules, functional components will be updated from beginning to end . As long as there is a change, all modules will be refreshed, which is obviously not necessary.

our ideal state is that each module only updates itself and does not influence each other, so using useMemo is the best solution at this time.

pay particular attention here. as long as the status of the parent component is updated, the child component will update regardless of whether the self-component is operated or not . useMemo is to prevent this

before we talk about useMemo , let's talk about memo , memo . The function of combines the pure components of pureComponent and the function of componentShouldUpdate . It compares the passed props, and then further determines which props needs to be updated according to the return value of the second function. (specific use will be discussed below)

The concept of

useMemo is similar to that of memo . It determines whether the callback function is executed by judging whether the current qualification is met, while the second parameter of useMemo is an array that determines whether to update the drop function

this method can be used in elements, components, and context , especially in arrays. Let's first look at an example:

    useMemo(() => (
        <div>
            {
                list.map((item, index) => (
                    <p key={index}>
                        {item.name}
                    </>
                )}
            }
        </div>
    ),[list])
undefined

from the above we can see that useMemo renders only when list changes, thus reducing unnecessary overhead

summarize the benefits of useMemo :

useCallback

useCallback is very similar to useMemo , except that useMemo returns the result of the function , while useCallback returns function

Note: this function is a function of the parent component passing child components to prevent irrelevant refreshes. Secondly, this component must cooperate with memo , otherwise will not improve performance, but may also degrade performance

      import React, { useState, useCallback } from 'react';
      import { Button } from 'antd-mobile';

      const MockMemo: React.FC<any> = () => {
        const [count,setCount] = useState(0)
        const [show,setShow] = useState(true)

        const  add = useCallback(()=>{
          setCount(count + 1)
        },[count])

        return (
          <div>
            <div style={{display: 'flex', justifyContent: 'flex-start'}}>
              <TestButton title="Normal click" onClick={() => setCount(count + 1) }/>
              <TestButton title="UseCallback Click" onClick={add}/>
            </div>
            <div style={{marginTop: 20}}>count: {count}</div>
            <Button onClick={() => {setShow(!show)}}> changing-over</Button>
          </div>
        )
      }

      const TestButton = React.memo((props:any)=>{
        console.log(props.title)
        return <Button color='primary' onClick={props.onClick} style={props.title === 'UseCallback Click' ? {
        marginLeft: 20
        } : undefined}>{props.title}</Button>
      })

      export default MockMemo;
undefined

We can see that when the switch button is clicked, the functions that are not encapsulated by useCallback will be refreshed again, while the functions wrapped by useCallback will not be refreshed again

useRef

useRef can get all the attributes of the current element and return a mutable ref object, and this object has only the current attribute , which can be set initialValue

get the corresponding attribute value through useRef

Let's look at a case first:

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

const Index:React.FC<any> = () => {
  const scrollRef = useRef<any>(null);
  const [clientHeight, setClientHeight ] = useState<number>(0)
  const [scrollTop, setScrollTop ] = useState<number>(0)
  const [scrollHeight, setScrollHeight ] = useState<number>(0)

  const onScroll = () => {
    if(scrollRef?.current){
      let clientHeight = scrollRef?.current.clientHeight; //Height of visible area
      let scrollTop  = scrollRef?.current.scrollTop;  //Scroll bar scroll height
      let scrollHeight = scrollRef?.current.scrollHeight; //Scrolling content height
      setClientHeight(clientHeight)
      setScrollTop(scrollTop)
      setScrollHeight(scrollHeight)
    }
  }

  return (
    <div >
      <div >
        <p>Height of visible area:{clientHeight}</p>
        <p>Scroll bar scroll height:{scrollTop}</p>
        <p>Scrolling content height:{scrollHeight}</p>
      </div>
      <div style={{height: 200, overflowY: 'auto'}} ref={scrollRef} onScroll={onScroll} >
        <div style={{height: 2000}}></div>
      </div>
    </div>
  );
};

export default Index;
undefined

from the above, we can do some operations by useRef to obtain the relevant attributes of the corresponding element.

cached data

in addition to getting the corresponding attribute values, useRef has another important feature: caching data

mentioned above, when we encapsulate a qualified custom hooks , we need to combine useMemo , useCallback and other Api, but we control the value of variables using useState may lead to get the old value, and if they update will cause the entire component to re-execute, in this case, we use useRef will be a very good choice

in the source code of react-redux , after the introduction of hooks, react-redux uses a large number of useMemo to redo Provide and other core modules, in which useRef is used to cache data, and none of the useRef () is bound to dom elements, they are all used for data caching

you can simply take a look:

    // Cache Data
    /* React redux uses userRef to cache the props after the merge*/ 
    const lastChildProps = useRef() 
    
    const lastWrapperProps = useRef(wrapperProps) 
    
    //Whether to update props or not is in the updating state 
    const renderIsScheduled = useRef(false)

    //Update data
    function captureWrapperProps( 
        lastWrapperProps, 
        lastChildProps, 
        renderIsScheduled, 
        wrapperProps, 
        actualChildProps, 
        childPropsFromStoreUpdate, 
        notifyNestedSubs 
    ) { 
        lastWrapperProps.current = wrapperProps 
        lastChildProps.current = actualChildProps 
        renderIsScheduled.current = false 
   }
undefined

We see that react-redux changes the cached data source and reduces unnecessary updates by re-assigning values. If we adopt useState , it is bound to render again

useLatest

through the above explanation, we know that useRef can get the latest value, and we can simply encapsulate it. The advantage of this is that can ensure that the latest value is obtained at any time, and it can also solve the closure problem

   import { useRef } from 'react';

   const useLatest = <T>(value: T) => {
     const ref = useRef(value)
     ref.current = value

     return ref
   };

   export default useLatest;
undefined
Exit mobile version