React Hooks useCallback 依赖无限循环
React Hooks useCallback dependency infinite loop
我目前在组件安装时获取一次数据,然后在用户单击按钮时获取一次。但是,如果请求正在进行中,我想停止获取按钮,这就是我更新 isFetching
状态的原因。
但是,我需要将 isFetching
添加到 useCallback
依赖项以删除警告,如果这样做,将触发无限获取循环。
这是我的代码:
import { useCallback, useEffect, useRef, useState } from 'react';
export const MyComponent = () => {
const isMounted = useRef(true);
const [isFetching, setIsFetching] = useState(false);
const [data, setData] = useState(null);
// Can also be called from the button click
const getMyData = useCallback(() => {
if (isFetching) return;
setIsFetching(true);
fetch('get/my/data')
.then((res) => {
if (isMounted.current) {
setData(res.data);
}
})
.catch((err) => {
if (isMounted.current) {
setData("Error fetching data");
}
})
.finally(() => {
if (isMounted.current) {
setIsFetching(false);
}
});
}, []); // isFetching dependency warning as is, if added then infinite loop
useEffect(() => {
isMounted.current = true;
getMyData();
return () => {
isMounted.current = false;
};
}, [getMyData]);
return (
<div>
<button onClick={getMyData}>Update data</button>
<p>{data}</p>
</div>
);
};
我知道有很多这样的问题,但我无法在检查组件是否已安装的同时删除警告或无限循环。
这里有一些例子:,
将 isFetching
转换为 ref,因此它的值不会成为函数的依赖项:
const { useCallback, useEffect, useRef, useState } = React;
const MyComponent = () => {
const isMounted = useRef(true);
const isFetching = useRef(false);
const [data, setData] = useState([]);
// Can also be called from the button click
const getMyData = useCallback(() => {
console.log('call');
if (isFetching.current) return;
isFetching.current = true;
fetch('https://cat-fact.herokuapp.com/facts')
.then(res => res.json())
.then(res => {
if (isMounted.current) {
setData(res);
}
})
.catch((err) => {
if (isMounted.current) {
setData("Error fetching data");
}
})
.finally(() => {
if (isMounted.current) {
isFetching.current = false;
}
});
}, []); // isFetching dependency warning as is, if added then infinite loop
useEffect(() => {
isMounted.current = true;
getMyData();
return () => {
isMounted.current = false;
};
}, [getMyData]);
return (
<div>
<button onClick={getMyData}>Update data</button>
<ul>
{
data.map(({ _id, text }) => (
<li key={_id}>{text}</li>
))
}
</ul>
</div>
);
};
ReactDOM.render(
<MyComponent />,
root
);
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div id="root"></div>
我目前在组件安装时获取一次数据,然后在用户单击按钮时获取一次。但是,如果请求正在进行中,我想停止获取按钮,这就是我更新 isFetching
状态的原因。
但是,我需要将 isFetching
添加到 useCallback
依赖项以删除警告,如果这样做,将触发无限获取循环。
这是我的代码:
import { useCallback, useEffect, useRef, useState } from 'react';
export const MyComponent = () => {
const isMounted = useRef(true);
const [isFetching, setIsFetching] = useState(false);
const [data, setData] = useState(null);
// Can also be called from the button click
const getMyData = useCallback(() => {
if (isFetching) return;
setIsFetching(true);
fetch('get/my/data')
.then((res) => {
if (isMounted.current) {
setData(res.data);
}
})
.catch((err) => {
if (isMounted.current) {
setData("Error fetching data");
}
})
.finally(() => {
if (isMounted.current) {
setIsFetching(false);
}
});
}, []); // isFetching dependency warning as is, if added then infinite loop
useEffect(() => {
isMounted.current = true;
getMyData();
return () => {
isMounted.current = false;
};
}, [getMyData]);
return (
<div>
<button onClick={getMyData}>Update data</button>
<p>{data}</p>
</div>
);
};
我知道有很多这样的问题,但我无法在检查组件是否已安装的同时删除警告或无限循环。
这里有一些例子:
将 isFetching
转换为 ref,因此它的值不会成为函数的依赖项:
const { useCallback, useEffect, useRef, useState } = React;
const MyComponent = () => {
const isMounted = useRef(true);
const isFetching = useRef(false);
const [data, setData] = useState([]);
// Can also be called from the button click
const getMyData = useCallback(() => {
console.log('call');
if (isFetching.current) return;
isFetching.current = true;
fetch('https://cat-fact.herokuapp.com/facts')
.then(res => res.json())
.then(res => {
if (isMounted.current) {
setData(res);
}
})
.catch((err) => {
if (isMounted.current) {
setData("Error fetching data");
}
})
.finally(() => {
if (isMounted.current) {
isFetching.current = false;
}
});
}, []); // isFetching dependency warning as is, if added then infinite loop
useEffect(() => {
isMounted.current = true;
getMyData();
return () => {
isMounted.current = false;
};
}, [getMyData]);
return (
<div>
<button onClick={getMyData}>Update data</button>
<ul>
{
data.map(({ _id, text }) => (
<li key={_id}>{text}</li>
))
}
</ul>
</div>
);
};
ReactDOM.render(
<MyComponent />,
root
);
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div id="root"></div>