【问题标题】:React "useViewBox" hook for SVG viewBox failing ESLint rule exhaustive-depsReact "useViewBox" hook for SVG viewBox 失败 ESLint 规则穷举-deps
【发布时间】:2021-01-05 18:02:57
【问题描述】:

我正在尝试创建一个方便的反应钩子,以使 SVG 的 viewBox 适合其内容。

import { useState } from 'react';
import { useEffect } from 'react';
import { useRef } from 'react';

// get fitted view box of svg
export const useViewBox = () => {
  const svg = useRef();
  const [viewBox, setViewBox] = useState(undefined);

  useEffect(() => {
    // if svg not mounted yet, exit
    if (!svg.current)
      return;
    // get bbox of content in svg
    const { x, y, width, height } = svg.current.getBBox();
    // set view box to bbox, essentially fitting view to content
    setViewBox([x, y, width, height].join(' '));
  });

  return [svg, viewBox];
};

然后使用它:

const [svg, viewBox] = useViewBox();

return <svg ref={svg} viewBox={viewBox}>... content ...</svg>

但我收到以下 eslint 错误:

React Hook useEffect contains a call to 'setViewBox'. Without a list of dependencies, this can lead to an infinite chain of updates. To fix this, pass [viewBox] as a second argument to the useEffect Hook.eslint(react-hooks/exhaustive-deps)

直到现在,我从未遇到过 react hooks eslint 错误是“错误”的情况。我觉得这是对钩子的完全合法使用。它需要作为效果运行,因为它需要在渲染后运行以查看 SVG 的内容是否已更改。至于警告消息:此代码已经避免了无限渲染循环,因为 setState 不会触发重新渲染,除非新值与当前值不同。

我可以禁用 eslint 规则:

// eslint-disable-next-line react-hooks/exhaustive-deps

但这似乎是错误的,我想知道是否有更简单/不同的方法来实现我没有看到的相同目标。

我可以让useViewBox 的调用者提供一些变量,这些变量将进入useEffect 的依赖数组并强制重新渲染,但我希望它比这更灵活、更易于使用。

或许问题实际上在于exhaustive-deps 规则。如果它在setState 前面检测到某些条件,也许它应该允许setState 在无依赖关系指定的useEffect 内...

【问题讨论】:

    标签: reactjs react-hooks eslint


    【解决方案1】:

    好的,我找到了一个“解决方案”,灵感来自 this answer。我认为这是一种愚蠢的解决方法,但我认为这比禁用 eslint 规则要好:

    import { useState } from 'react';
    import { useEffect } from 'react';
    import { useRef } from 'react';
    import { useCallback } from 'react';
    
    // get fitted view box of svg
    export const useViewBox = () => {
      const svg = useRef();
      const [viewBox, setViewBox] = useState(undefined);
    
      const getViewBox = useCallback(() => {
        // if svg not mounted yet, exit
        if (!svg.current)
          return;
        // get bbox of content in svg
        const { x, y, width, height } = svg.current.getBBox();
        // set view box to bbox, essentially fitting view to content
        setViewBox([x, y, width, height].join(' '));
      }, []);
    
      useEffect(() => {
        getViewBox();
      });
    
      return [svg, viewBox];
    };
    

    【讨论】:

    • 我以前也必须这样做,我想知道为什么首先抛出 es lint 规则,迫使我们使用此解决方法或禁用 es lint 规则。令人费解。
    猜你喜欢
    • 1970-01-01
    • 2019-11-20
    • 2020-06-09
    • 2022-08-18
    • 1970-01-01
    • 2021-04-18
    • 1970-01-01
    • 2020-03-11
    相关资源
    最近更新 更多