iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >React HooksuseReducer 逃避deps组件渲染次数增加陷阱
  • 763
分享到

React HooksuseReducer 逃避deps组件渲染次数增加陷阱

2024-04-02 19:04:59 763人浏览 独家记忆
摘要

目录前言自定义 Hooks 简单实现在组件中使用自定义 Hooks提前阻止 dispatch 触发优化后再测试结论题外前言 在快乐使用 React Hooks 开发自定义 Hooks

前言

在快乐使用 React Hooks 开发自定义 Hooks 过程中,使用了 useEffectuseReduceruseRefuseCallback 等官方提供的 Hooks,将一些通用逻辑抽离出来,提高代码复用性。

但在组合使用 useEffectuseReducerReact.memo 时,发生了组件在状态未发生变化时触发渲染,因为此动作发生在 mousemove 鼠标移动时,所以组件不必要渲染次数非常多。

自定义 Hooks 简单实现

import { useReducer } from "react";
const reducer = (state, action) => {
  const { sliding, lastPos, ratio } = state;
  switch (action.type) {
    case "start":
      return {
        ...state,
        slideRange: action.slideRange,
        lastPos: action.x,
        sliding: true,
      };
    case "move":
      if (!sliding) {
        return state;
      }
      const offsetX = action.x - lastPos;
      const newRatio = ratio + offsetX / state.slideRange;
      if (newRatio > 1 || newRatio < 0) {
        return state;
      }
      return {
        ...state,
        lastPos: action.x,
        ratio: newRatio,
      };
    case "end":
      if (!sliding) {
        return state;
      }
      return {
        ...state,
        sliding: false,
      };
    case "updateRatio":
      return {
        ...state,
        ratio: action.ratio,
      };
    default:
      return state;
  }
};
export function useSlider(initialState) {
    const [state, dispatch] = useReducer(reducer, initialState);
    return [state, dispatch];
}

在组件中使用自定义 Hooks

const [state, dispatch] = useSlider(initialState);
  const { ratio, sliding, lastPos, slideRange } = state;
  useEffect(() => {
    const onSliding = (e) => {
      dispatch({ type: "move", x: e.pageX });
    };
    const onSlideEnd = () => {
      dispatch({ type: "end" });
    };
    document.addEventListener("mousemove", onSliding);
    document.addEventListener("mouseup", onSlideEnd);
    return () => {
      document.removeEventListener("mousemove", onSliding);
      document.removeEventListener("mouseup", onSlideEnd);
    };
  }, [dispatch]);
  const handleThumbMouseDown = useCallback(
    (event) => {
      const hotArea = hotAreaRef.current;
      dispatch({
        type: "start",
        x: event.pageX,
        slideRange: hotArea.clientWidth,
      });
      if (event.target.className !== "point") {
        dispatch({
          type: "updateRatio",
          ratio: (event.pageX - 30) / hotArea.clientWidth,
        });
      }
    },
    [dispatch]
  );

鼠标每次移动,都会触发 dispatch({ type: "move", x: e.pageX }),在 reducer 函数中,当 !sliding 时,不修改 state 数据原样返回,但是组件仍然进行了渲染。

提前阻止 dispatch 触发

sliding 判断移动到 useEffect 中,提前阻止 dispatch 触发,并将 sliding 设置到 useEffect(fn, deps) deps 中,保证监听函数中能取到 sliding 最新值。

useEffect(() => {
    const onSliding = (e) => {
      if(!sliding) {
        return;
      }
      dispatch({ type: "move", x: e.pageX });
    };
    const onSlideEnd = () => {
      if (!sliding) {
        return;
      }
      dispatch({ type: "end" });
    };
    document.addEventListener("mousemove", onSliding);
    document.addEventListener("mouseup", onSlideEnd);
    return () => {
      document.removeEventListener("mousemove", onSliding);
      document.removeEventListener("mouseup", onSlideEnd);
    };
  }, [sliding]);

优化后再测试

鼠标仅移动时,slidingfalse,直接 return,不会触发 dispatch 动作。

好处

避免了组件在 state 未修改时不必要渲染。

坏处

部分处理逻辑被移动到使用自定义 hooks 的组件中,sliding 数据改变时,add EventListener函数会重新注册。

结论

不能为了不在 useEffect(fn, deps) 设置 deps,使用 useReducer,并把所有数据变更都放在 reducer 中。 本篇文章通过把不修改 reducer state 的动作提前阻止,避免使用此自定义 hooks 的组件发生不必要渲染,提高代码复用性的同时也兼顾了组件性能。

题外

  • React.memoprops 进行浅比较,一种组件性能优化方式
  • useCallback(fn, deps) 缓存函数
  • useMemo(() => fn, deps) 缓存昂贵变量
  • useState(initialState)惰性初始stateinitialState` 只会在组件初始渲染中起作用,后续渲染时会被

参考文献

React 官方文档

以上就是React Hooks 之 useReducer 逃避deps后增加组件渲染次数的陷阱的详细内容,更多关于React Hooks useReducer组件渲染的资料请关注编程网其它相关文章!

--结束END--

本文标题: React HooksuseReducer 逃避deps组件渲染次数增加陷阱

本文链接: https://www.lsjlt.com/news/166988.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作