英文:
How to keep track of the object reference in a useEffect?
问题
I'm building some API hooks and I have trouble with deps
property. I want to reinvoke the useEffect
when content of deps
changes, instead I'm running in a forever loop. deps
can be either undefined or an any[]
.
export const useReader = <TResponseData>({ url, deps, options }: TypeUseReader<TResponseData>) => {
const [data, setData] = useState<TResponseData | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [error, setError] = useState<number | null >(null);
async function fetchData(newUrl?: string) {}
useEffect(() => {
// ..fetch
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [url, deps]); // HERE, deps are forever loop
return {
data,
isLoading,
error,
fetchData
};
};
That's how I'm using it:
return useReader<FOO>(
{
url: 'URL_PLACEHOLDER',
deps: [anything] /* FIXME: deps enters FOREVER LOOP */
}
);
What I have tried:
[deps ?? []]
and ...[deps ?? []]
and deps
- all of these create forever loop
英文:
I'm building some API hooks and I have trouble with deps
property. I want to reinvoke the useEffect
when content of deps
changes, instead I'm running in a forever loop. deps
can be either undefined or an any[]
export const useReader = <TResponseData>({ url, deps, options }: TypeUseReader<TResponseData>) => {
const [data, setData] = useState<TResponseData | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [error, setError] = useState<number | null >(null);
async function fetchData(newUrl?: string) {}
useEffect(() => {
// ..fetch
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [url, deps]); // HERE, deps are forever loop
return {
data,
isLoading,
error,
fetchData
};
};
That's how I'm using it:
return useReader<FOO>(
{
url: 'URL_PLACEHOLDER',
deps: [anything] /* FIXME: deps enters FOREVER LOOP */
}
);
What I have tried:
[deps ?? []]
and ...[deps ?? []]
and deps
- all of these create forever loop
答案1
得分: 0
The problem is that when you're calling useReader
with deps
as an array literal, a new array is being created each time, so useEffect
rightly detects a change in the value.
Broadly speaking, there are two ways to deal with this.
You can make it the responsibility of the caller – specify in the useReader
interface that it accepts a single dep
value of unknown
type. If the caller wants to pass through an array of values, then these should be stabilized, e.g.
const dep = useMemo(() => [val1, val2], [val1, val2]);
return useReader<FOO>(
{
url: 'URL_PLACEHOLDER',
isSuspended: false,
initialValue: foo,
dep /* only changes if val1 or val2 has changed */
}
);
Easier and more flexible is to accept an array of deps
(typed as unknown[]
), and just spread the members of the array after the other dependencies you're passing to useEffect
:
useEffect(() => {
if (!isSuspended) {
fetchData();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isSuspended, url, ...(deps ?? [])]);
The various linters do get upset about this, but it's not problematic as far as the hook machinery is concerned.
英文:
The problem is that when you're calling useReader
with deps
as an array literal, a new array is being created each time, so useEffect
rightly detects a change in the value.
Broadly speaking, there are two ways to deal with this.
You can make it the responsibility of the caller – specify in the useReader
interface that it accepts a single dep
value of unknown
type. If the caller wants to pass through an array of values, then these should be stabilized, e.g.
const dep = useMemo(() => [val1, val2], [val1, val2]);
return useReader<FOO>(
{
url: 'URL_PLACEHOLDER',
isSuspended: false,
initialValue: foo,
dep /* only changes if val1 or val2 has changed */
}
);
Easier and more flexible is to accept an array of deps
(typed as unknown[]
), and just spread the members of the array after the other dependencies you're passing to useEffect
:
useEffect(() => {
if (!isSuspended) {
fetchData();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isSuspended, url, ...(deps ?? [])]);
The various linters do get upset about this, but it's not problematic as far as the hook machinery is concerned.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论