Skip to content

我真的不适合写React

我们最近在写一个关于service charge,有点类似于VAT(value added tax)这块的需求,前端需要涉及到一些价格计算,我们是在服务端返回演出清单时,需要在每个演出的价格中加上这个service charge(其实可以后端先把价格计算好返回给前端更好一些),不过我们暂时没有这么做,那么前端就需要在得到返回数据后增加一个useMemo来计算出最终的价格,但是出现的bug是service charge数额被计算两次,简单来说就是本来需要增加10美元,结果增加了20美元,我自己调试了很久(预计浪费了2个小时左右)还是没有找出原因。后来请同事帮忙查看,也是没有结果。

export function useQueryClubEvents(args?: UseQueryArgs) {
  const query = useQuery<Response, Error>({
    queryKey: keys.listWithFilter(params),
    queryFn: () => fetcher(`/api/user/events`),
    ...args,
  })

  return useMemo(() => {
    const res = query.data
    if (!res?.data?.length) return query

    const updatedEvents = res.data.map(event => {
      const serviceCharge = event.serviceCharge
      if (!serviceCharge) return event

      if (!hasArrayLength(tickets)) return event

      event.tickets = getTicketTypesWithServiceCharge(
        tickets,
        serviceCharge
      )

      return event
    })

    return { data: { ...res, data: updatedEvents } }

    // Re-calculate only when data changes
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [query?.data?.data]) as typeof query
}

最后同事发现,原来是我们直接修改了原始event的tickets,这样做直接修改了useMemo的依赖项,所有导致useMemo执行了两次。所以需要复刻一个event,然后再执行后面的操作。

export function useQueryClubEvents(args?: UseQueryArgs) {
  const query = useQuery<Response, Error>({
    queryKey: keys.listWithFilter(params),
    queryFn: () => fetcher(`/api/user/events`),
    ...args,
  })

  return useMemo(() => {
    const res = query.data
    if (!res?.data?.length) return query

    const updatedEvents = res.data.map(event => {
      const newEvent = {...event}
      const serviceCharge = newEvent.serviceCharge
      if (!serviceCharge) return newEvent

      if (!hasArrayLength(tickets)) return newEvent

      newEvent.tickets = getTicketTypesWithServiceCharge(
        tickets,
        serviceCharge
      )

      return newEvent
    })

    return { data: { ...res, data: updatedEvents } }

    // Re-calculate only when data changes
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [query?.data?.data]) as typeof query
}

React最让人头疼的一点就是时时刻刻需要考虑避免组件不必要的重新渲染,以及memo一些数据,这点和使用Signal的SolidJS或者使用compiler的Svelte简直没法比,当开发者把精力全部放在考虑优化性能上(即使做到很好,React的性能还是远远比不上其他框架),那么放在具体业务需求上的精力就少了。React已经是10年的产品了,优缺点很多,但是随着Web Components的兴起,很高兴看到很多项目从React转到更趋向于Web Platform标准的技术了。

访客留言

  1. 还是作者本人,不过只是从另外一个浏览器打开而已,测试一下这个留言表单的使用体验。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注