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

March 30, 2023 1448hotness 0likes 0comments

encapsulate useCreation with useMemo and useRef

useCreation : is a substitute for useMemo or useRef . In other words, the useCreation hook enhances useMemo and useRef so that the hook can replace the two hooks. (from ahooks-useCreation)

  • useMemo is not necessarily the latest value, but useCreation ensures that the value you get must be the latest value
  • for the creation of complex constants, useRef is prone to potential performance risks, but useCreation can avoid

the performance hazard here refers to:

   // Every time you re render, the process of instantiating the Subject is executed, even if the instance is immediately thrown away
   const a = useRef(new Subject()) 
   
   //Performance hazards can be avoided through the factory function
   const b = useCreation(() => new Subject(), []) 
undefined

next let's look at how to encapsulate a useCreation . First, we need to understand the following three points:

  • the first point: determine the parameters first. The parameters of useCreation are the same as those of useMemo . The first parameter is a function, and the second parameter is a variable array
  • .

  • second point: our values should be saved in useRef , so that the values can be cached, thus reducing extraneous refreshes
  • the third point: the judgment of updating value, how to determine whether to update the value in useRef by the second parameter.

if we understand three things, we can implement a useCreation

ourselves.

import { useRef } from 'react';
import type { DependencyList } from 'react';

const depsAreSame = (oldDeps: DependencyList, deps: DependencyList):boolean => {
  if(oldDeps === deps) return true
  
  for(let i = 0; i < oldDeps.length; i++) {
    // Determine whether two values are the same value
    if(!Object.is(oldDeps[i], deps[i])) return false
  }

  return true
}

const useCreation = <T>(fn:() => T, deps: DependencyList)=> {

  const { current } = useRef({ 
    deps,
    obj:  undefined as undefined | T ,
    initialized: false
  })

  if(current.initialized === false || !depsAreSame(current.deps, deps)) {
    current.deps = deps;
    current.obj = fn();
    current.initialized = true;
  }

  return current.obj as T
} 

export default useCreation;
undefined

in useRef , the updated value is judged by initialized and depsAreSame , in which depsAreSame compares the deps (old value) stored in useRef with the newly passed deps (new value) to determine whether the data of the two arrays are consistent and whether to update

verify useCreation

Let's write a small example to verify whether useCreation meets our requirements:

    import React, { useState } from 'react';
    import { Button } from 'antd-mobile';
    import { useCreation } from '@/components';

    const Index: React.FC<any> = () => {
      const [_, setFlag] = useState<boolean>(false)

      const getNowData = () => {
        return Math.random()
      }

      const nowData = useCreation(() => getNowData(), []);

      return (
        <div style={{padding: 50}}>
          <div>Normal functions: {getNowData()}</div>
          <div>UseCreation Wrapped: {nowData}</div>
          <Button color='primary' onClick={() => {setFlag(v => !v)}}> Render</Button>
        </div>
      )
    }

    export default Index;
undefined

We can see that when we make irrelevant state changes, the normal function is refreshed, but useCreation is not refreshed, thus enhancing the performance of rendering ~

useEffect

useEffect I believe that what you have already used cannot be ripe again. We can use useEffect to simulate the componentDidMount and componentWillUnmount functions of class .

useMount

Needless to say, this hook simplifies the second parameter of useEffect :

    import { useEffect } from 'react';

    const useMount = (fn: () => void) => {

      useEffect(() => {
        fn?.();
      }, []);
    };

    export default useMount;
undefined

useUnmount

one thing to note about this is to use useRef to ensure that the passed function is in the latest state, so you can use

with useLatest mentioned above.

    import { useEffect, useRef } from 'react';

    const useUnmount = (fn: () => void) => {

      const ref = useRef(fn);
      ref.current = fn;

      useEffect(
        () => () => {
          ref.current()
        },
        [],
      );
    };

    export default useUnmount;
undefined

combine useMount and useUnmount to make a small example

    import { Button, Toast } from 'antd-mobile';
    import React,{ useState } from 'react';
    import { useMount, useUnmount } from '@/components';

    const Child = () => {

      useMount(() => {
        Toast.show('First render')
      });

      useUnmount(() => {
        Toast.show('Component uninstalled')
      })

      return <div>Hello, I'm Star</div>
    }

    const Index:React.FC<any> = (props)=> {
      const [flag, setFlag] = useState<boolean>(false)

      return (
        <div style={{padding: 50}}>
          <Button color='primary' onClick={() => {setFlag(v => !v)}}>changing-over {flag ? 'unmount' : 'mount'}</Button>
          {flag && <Child />}
        </div>
      );
    }

    export default Index;
undefined

useUpdate

useUpdate : force updates

sometimes we need a component to force updates, so we can use this hook:

    import { useCallback, useState } from 'react';

    const useUpdate = () => {
      const [, setState] = useState({});

      return useCallback(() => setState({}), []);
    };

    export default useUpdate;
    
    //Example:
    import { Button } from 'antd-mobile';
    import React from 'react';
    import { useUpdate } from '@/components';


    const Index:React.FC<any> = (props)=> {
      const update = useUpdate();

      return (
        <div style={{padding: 50}}>
          <div>Time:{Date.now()}</div>
          <Button color='primary' onClick={update}>Update time</Button>
        </div>
      );
    }

    export default Index;
undefined
InterServer Web Hosting and VPS

Aaron

Hello, my name is Aaron and I am a freelance front-end developer

Comments