我正在尝试创建一个方便的反应挂钩,以使其内容适合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
前面检测到某些条件,则应该允许useEffect
在无依赖项指定的setState
中。
答案 0 :(得分: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];
};