Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

自定义hook #15

Open
iloveyou11 opened this issue Apr 20, 2021 · 0 comments
Open

自定义hook #15

iloveyou11 opened this issue Apr 20, 2021 · 0 comments
Labels

Comments

@iloveyou11
Copy link
Owner

为什么要用自定义hook函数?

《超性感的React Hooks(五):自定义hooks》讲得非常清楚,建议阅读。

其实自定义hook类似于我们平常的函数封装,也有点类似于装饰器,我们只用关注自己的操作逻辑即可,至于操作之后会发生什么,都交给hook来处理(如改变数组之后会发生什么、伸缩窗口大小后会发生什么)。这无疑是一次思维方式的减负。利用这样的特性,我们就不再关注额外的逻辑,而只需要关注操作本身即可。

在React Hooks中,这样的自定义方法,我们就可以称之为自定义Hooks。所有的自定义hooks都会以use开头,以表示该方法只能在函数式组件中使用。

自定义hook能够跟随函数组件重复执行,并且每次都返回最新结果。因此,我们可以非常放心大胆的封装异步逻辑。

React Hooks常用api,包括useState、useCallback,useMemo等,其实都是自定义的hooks。后续可以了解下源码实现。还有更多的useHooks函数,可以参考useHooks

useEqualArr——操作数组,自动计算是否相等

import { useState } from 'react';

function equalArr(a: number[], b: number[]) {
  if (a.length !== b.length) {
    return false;
  }
  if (a.length === 0 && b.length === 0) {
    return true;
  }
  return a.every((item, i) => item === b[i]);
}

export default function useEqualArr() {
  const [arrA, setArrA] = useState<number[]>([]);
  const [arrB, setArrB] = useState<number[]>([]);
  const isEqual = equalArr(arrA, arrB);

  return {
    arrA,
    setArrA,
    arrB,
    setArrB,
    isEqual
  }
}

定义完成之后,直接在自身项目中const {arrA, arrB, setArrA, setArrB, isEqual} = useEqualArr()使用即可。只用关注arrA、arrB的数组改变操作,而不用再每次额外计算两个数组是否相等了。

useInitial——初始化时加载至少一个接口,而这个接口有一些统一的处理逻辑可以抽离,例如请求成功,返回数据,请求失败,异常处理,特定时机下刷新

import {useState, useEffect} from 'react';

export default function useInitial<T, P>(
  api: (params: P) => Promise<T>,
  params: P,
  defaultData: T
) {
  const [loading, setLoading] = useState(true);
  const [response, setResponse] = useState(defaultData);
  const [errMsg, setErrmsg] = useState('');

  useEffect(() => {
    if (!loading) { return };
    getData();
  }, [loading]);

  function getData() {
    api(params).then(res => {
      setResponse(res);
    }).catch(e => {
      setErrmsg(errMsg);
    }).finally(() => {
      setLoading(false);
    })
  }

  return {
    loading,
    setLoading,
    response,
    errMsg
  }
}

定义完hook之后,直接在项目中即可使用:

export default function FunctionDemo() {
    // 只需要传入api, 对应的参数与返回结果的初始默认值即可
    const {loading, setLoading, response, errMsg} = useInitial(api, {id: 10}, {});
}

usePointor——跟踪鼠标的实时位置。例如拖拽,K线图,走马灯等场景都会需要用到这个逻辑片段

export default function usePointor() {
  const [position, setPosition] = useState({x: 0, y: 0});
  const handleMouseMove = (event: React.MouseEvent<HTMLDivElement, any>) => {
    setPosition({x: event.clientX, y: event.clientY});
  }
  return {position, handleMouseMove}
}

定义完成后,直接使用:

export default function MousePos() {
  const {position, handleMouseMove} = usePointor();
  return (
    <div onMouseMove={handleMouseMove} style={{width: 500, height: 500}}>
      <div>x: {position.x}, y: {position.y}</div>
    </div>
  );
}

useWindowSize——获取窗口尺寸

const getSize = () => {
  return {
    innerHeight: window.innerHeight,
    innerWidth: window.innerWidth,
    outerHeight: window.outerHeight,
    outerWidth: window.outerWidth
  };
}

function useWindowSize() {
  let [windowSize, setWindowSize] = useState(getSize());

  function handleResize() {
    setWindowSize(getSize());
  }

  useEffect(() => {
    window.addEventListener("resize", handleResize);
    return () => {
      window.removeEventListener("resize", handleResize);
    };
  }, []);

  return windowSize
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant