I Love ReactJS

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

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)

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:

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
Exit mobile version