我可以在 useEffect 中调用单独的函数吗?
Can I call separate function in useEffect?
我可以在 useEffect 中调用另一个单独的函数吗?
我正在调用 useEffect 中的另一个函数,但在保存文件后,它会自动将该函数添加到 useEffect 的数组参数中。
请参阅下面的代码以正确理解。
保存文件前:
useEffect(() => {
getData()
console.log("useEffect ran...");
}, [query]);
function getData() {
fetch(`https://jsonplaceholder.typicode.com/${query}`)
.then(response => response.json())
.then(json => setData(json));
}
保存文件后:
useEffect(() => {
getData();
console.log("useEffect ran...");
}, [getData, query]);
function getData() {
fetch(`https://jsonplaceholder.typicode.com/${query}`)
.then(response => response.json())
.then(json => setData(json));
}
又是运行。
由于您在 React 组件中声明了 getData
函数,因此它在每次渲染时都是 re-created,因此效果的依赖性在每次渲染时都会发生变化。这就是每次渲染都执行效果的原因。
为防止这种情况,您应该在组件外部声明 getData
函数,然后传递查询。像这样:
function getData(query) {
return fetch(`https://jsonplaceholder.typicode.com/${query}`)
.then(response => response.json());
}
function YouComponent({ query }) {
...
useEffect(() => {
getData(query).then(setData);
console.log("useEffect ran...");
}, [query]);
...
P.S: 我不确定 eslint 插件在这样做时是否会自动将 getData 添加到依赖项中,但即使这样做也不会造成伤害。
如果将 getData
函数移动到 useEffect
中,则不必将其作为依赖项包含在内,并且 useEffect
仅 运行 当 query
变化。
尝试将 getData 函数包装在 useCallback 钩子中,并在调用 getData 时将其放在 component.So 之外,这样它就不会一直 return 一个新函数,因此它会阻止组件来自重新渲染
已接受的答案在某种程度上具有误导性。在组件内部定义函数显然会在每次渲染时重新创建。但是不代表在useEffect hook里面使用的时候每次render都会重新调用。
保存文件代码后的关键问题是您正在监视 getData。因为它在每个渲染器上重新创建,所以 useEffect 接受它作为更改,因此导致您在每个渲染器上重新 运行。 简单的解决方法是不观看 getData。
但很明显,正如接受的答案中所建议的那样。更好的做法是将函数分离到组件外部,这样它就不会在每次渲染时重新创建。
坦率地说,如果我是你,我不会只为 fetch 定义函数:
useEffect(() => {
fetch(`https://jsonplaceholder.typicode.com/${query}`)
.then(response => response.json())
.then(json => setData(json));
}, [query]); // only re-run on query change
长话短说;博士
使用 useCallback()
首先,让一个函数成为依赖是很危险的。如果该函数导致状态更改,则随后的重新渲染将再次调用该函数(通过 useEffect)...并开始无限循环。
您可以做的一件事就是在 useEffect() 方法本身中创建函数。
useEffect(() => {
function getData() {
fetch(`https://jsonplaceholder.typicode.com/${query}`)
.then(response => response.json())
.then(json => setData(json));
}
}
getData();
console.log("useEffect ran...");
}, [query]);
}
或者干脆
useEffect(() => {
(() => {
fetch(`https://jsonplaceholder.typicode.com/${query}`)
.then(response => response.json())
.then(json => setData(json)
)();
}, [query]);
}
话虽如此,有时您仍然希望在 useEffect 之外声明函数,以便 code-reuse。这次您需要确保它不会在每次渲染期间重新创建。为此,您可以
在组件外部声明函数——这会强制您将所有变量作为参数传递....这很痛苦
将其包裹在 useMemo()
或 useCallback()
内
这是一个例子
const getData = useCallback(()=>{...}, []);
您还可以使用 useRef
to create a ref and put the function definition there and call it using ref.current()
. Even React supports 使用 ref 作为实例变量。
useRef
returns a mutable ref object whose .current
property is initialized to the passed argument (initialValue
). The returned object will persist for the full lifetime of the component.
However, useRef()
is useful for more than the ref
attribute. It’s handy for keeping any mutable value around similar to how you’d use instance fields in classes.
useEffect(() => {
getData.current()
console.log("useEffect ran...");
}, [query]);
const getData = useRef(() {
fetch(`https://jsonplaceholder.typicode.com/${query}`)
.then(response => response.json())
.then(json => setData(json));
});
重要:
如果你想在这个方法中使用任何状态变量,那么你必须创建一个可变对象(像另一个引用),它将包含状态的最新值,就像你直接引用其中的状态变量一样那么它将引用在创建方法时创建的 old/default 值。要了解更多信息,您可以 。 useCallback
方法也是如此。
我可以在 useEffect 中调用另一个单独的函数吗?
我正在调用 useEffect 中的另一个函数,但在保存文件后,它会自动将该函数添加到 useEffect 的数组参数中。
请参阅下面的代码以正确理解。
保存文件前:
useEffect(() => {
getData()
console.log("useEffect ran...");
}, [query]);
function getData() {
fetch(`https://jsonplaceholder.typicode.com/${query}`)
.then(response => response.json())
.then(json => setData(json));
}
保存文件后:
useEffect(() => {
getData();
console.log("useEffect ran...");
}, [getData, query]);
function getData() {
fetch(`https://jsonplaceholder.typicode.com/${query}`)
.then(response => response.json())
.then(json => setData(json));
}
又是运行。
由于您在 React 组件中声明了 getData
函数,因此它在每次渲染时都是 re-created,因此效果的依赖性在每次渲染时都会发生变化。这就是每次渲染都执行效果的原因。
为防止这种情况,您应该在组件外部声明 getData
函数,然后传递查询。像这样:
function getData(query) {
return fetch(`https://jsonplaceholder.typicode.com/${query}`)
.then(response => response.json());
}
function YouComponent({ query }) {
...
useEffect(() => {
getData(query).then(setData);
console.log("useEffect ran...");
}, [query]);
...
P.S: 我不确定 eslint 插件在这样做时是否会自动将 getData 添加到依赖项中,但即使这样做也不会造成伤害。
如果将 getData
函数移动到 useEffect
中,则不必将其作为依赖项包含在内,并且 useEffect
仅 运行 当 query
变化。
尝试将 getData 函数包装在 useCallback 钩子中,并在调用 getData 时将其放在 component.So 之外,这样它就不会一直 return 一个新函数,因此它会阻止组件来自重新渲染
已接受的答案在某种程度上具有误导性。在组件内部定义函数显然会在每次渲染时重新创建。但是不代表在useEffect hook里面使用的时候每次render都会重新调用。
保存文件代码后的关键问题是您正在监视 getData。因为它在每个渲染器上重新创建,所以 useEffect 接受它作为更改,因此导致您在每个渲染器上重新 运行。 简单的解决方法是不观看 getData。
但很明显,正如接受的答案中所建议的那样。更好的做法是将函数分离到组件外部,这样它就不会在每次渲染时重新创建。
坦率地说,如果我是你,我不会只为 fetch 定义函数:
useEffect(() => {
fetch(`https://jsonplaceholder.typicode.com/${query}`)
.then(response => response.json())
.then(json => setData(json));
}, [query]); // only re-run on query change
长话短说;博士
使用 useCallback()
首先,让一个函数成为依赖是很危险的。如果该函数导致状态更改,则随后的重新渲染将再次调用该函数(通过 useEffect)...并开始无限循环。
您可以做的一件事就是在 useEffect() 方法本身中创建函数。
useEffect(() => {
function getData() {
fetch(`https://jsonplaceholder.typicode.com/${query}`)
.then(response => response.json())
.then(json => setData(json));
}
}
getData();
console.log("useEffect ran...");
}, [query]);
}
或者干脆
useEffect(() => {
(() => {
fetch(`https://jsonplaceholder.typicode.com/${query}`)
.then(response => response.json())
.then(json => setData(json)
)();
}, [query]);
}
话虽如此,有时您仍然希望在 useEffect 之外声明函数,以便 code-reuse。这次您需要确保它不会在每次渲染期间重新创建。为此,您可以
在组件外部声明函数——这会强制您将所有变量作为参数传递....这很痛苦
将其包裹在
useMemo()
或useCallback()
内
这是一个例子
const getData = useCallback(()=>{...}, []);
您还可以使用 useRef
to create a ref and put the function definition there and call it using ref.current()
. Even React supports 使用 ref 作为实例变量。
useRef
returns a mutable ref object whose.current
property is initialized to the passed argument (initialValue
). The returned object will persist for the full lifetime of the component.
However,
useRef()
is useful for more than theref
attribute. It’s handy for keeping any mutable value around similar to how you’d use instance fields in classes.
useEffect(() => {
getData.current()
console.log("useEffect ran...");
}, [query]);
const getData = useRef(() {
fetch(`https://jsonplaceholder.typicode.com/${query}`)
.then(response => response.json())
.then(json => setData(json));
});
重要:
如果你想在这个方法中使用任何状态变量,那么你必须创建一个可变对象(像另一个引用),它将包含状态的最新值,就像你直接引用其中的状态变量一样那么它将引用在创建方法时创建的 old/default 值。要了解更多信息,您可以 useCallback
方法也是如此。