React 踩坑记录

302 阅读3分钟

日常踩坑总结

日常项目开发中遇到的 React 相关的各种各样的问题。这里都会以背景、问题、解决方案三块来记录分享给大家,希望自己和其他小伙伴在以后写 BUG 的日子里避免踩相同的坑,提升开发效率,增加摸鱼时间。持续更新中...

项目技术栈:React、nextjs、useSWR、Parse、TypeScript

Hook 嵌套

列表特殊组件渲染

代码结构设计真的很重要

背景

一个 Table 中的某一列要渲染一个特定组件,这个组件会根据接受的 id 去请求对应的数据用于渲染,然后大列表中会一次发出 pageSize 个请求,不过 id 可能会有重复的,在请求那边,想同的入参会直接返回上次的数据,不会再发真正的请求。

问题

一次性发出多个请求, Chrome http1.1 中一次最多发送 6 条请求,会造成很大的性能问题,这里需要把所有的请求合并,应该一次请求去发送。 理论上应该在父组件上拿到所有的 id 然后去发一个请求的,但结构设计不是每个人都会去深度考虑的,初级开发者在日常工作中可能就是去为了完成需求而开发,不是每个人都会去考虑可用性和可能带来的性能问题。

ps: 没办法改组件,影响太大,时间不够,所以没有把请求拿到父组件去,下边给一个临时解决方案

解决方案

在 useFetchHook 中, 用自定义的 throttle 把请求方法包裹一层,在 wait 时间内,拼接所有请求的参数,之后发出请求,拿到数据,放入 Context 中,期间所有的请求都直接返回 resolve。

/**
 * @description 能够缓存参数的节流方法
 * @param {function} func 目标方法。间隔时间后,将期间缓存的参数一并传入
 * @param {number} wait 间隔毫秒数
 * @category 高阶函数
 */
export function genThrottleCacheFunc(func: (arg0: any, arg1?: any) => any, wait: number): any {
  let timer: NodeJS.Timeout;
  let paramsArr = [];
  let result = [];
  return async (type: any, params, oldData, setData) => {
    paramsArr = union(paramsArr, params);
    // 存在回调则返回 Promise.resolve
    if (timer) return Promise.resolve();
    timer = setTimeout(async () => {
      // 单位时间结束后
      result = await func.call(this, type, paramsArr);
      clearTimeout(timer);
      timer = null;
      paramsArr = [];
      setData(uniqBy([...oldData, ...result], 'id'));
      return result;
    }, wait);
  };
}

// 外层调用直接
const curFetch = genThrottleCacheFunc(fetch, 500)

目前解决方案为这样,后续如果有更好的,会再更新

useMemo & 自定义 Hook

请求参数都要用 useMemo包裹,常量也需要包裹进去

背景

需要改动一个列表中组件的请求方式,通过传入参数的方式区分,且参数固定,所以就在入参的对象中添加了 type: true

感觉上代码比清晰

const ids = useMemo(() => [value].filter(Boolean), [value]);
// 改动前
const {data} = useFetch({ ids })
// 改动后
const {data} = useFetch({ ids, type: true })

问题

在虚拟列表滚动时,渲染过的组件在离开视口后再次进入视口,会再次发起请求。以前是没有的,useFetch 中使用的 useSWR,key 不变会把上次请求的数据返回回来

解决方案

//改动前
const ids = useMemo(() => [value].filter(Boolean), [value]);
const {data} = useFetch({ ids, type: true })

// 改动后
const ids = useMemo(() => [value].filter(Boolean), [value]);
const params = useMemo(() => ({ids, type: true}), [ids])
const {data} = useFetch(params)

闭坑闭坑啊


后续再遇到问题和填的坑都会更新到本文中,不求点赞关注,您阅读到就是我最大的幸运。如果能留下您宝贵的意见或者分享自己遇到过的坑,那将万分感谢!!