反应 - useEffect 与 setInterval
React - useEffect with setInterval
我有一个 useEffect
里面有 setInterval
的功能组件。
但是 loadData
中的值始终等于初始值(0),尽管渲染正确。
如何在 loadData
中获取 setInterval
调用的当前 value
?
...
const [value, setValue] = useState(0);
const [service, setService] = useState();
useEffect(() => {
setService(new ApiService());
}, [])
useEffect(
() => {
const timerId = setInterval(loadData, 1000 * 5);
return () => clearInterval(timerId);
},
[service]
)
async function loadData() {
const result = await service.getData();
console.log("old value: ", value); // "value" is always 0 (initial)
setValue(result.data.value);
}
...
您可以更改 useEffect()
挂钩的依赖项数组,目前由于 loadData
在 value
上关闭,您最终将处于陈旧状态:
const loadData = useCallback(async function() {
const result = await service.getData();
console.log("old value: ", value); // "value" is always 0 (initial)
setValue(result.data.value);
}, [service, value]);
useEffect(() => {
const timerId = setInterval(loadData, 1000 * 5);
return () => clearInterval(timerId);
}, [loadData]);
以上将您的函数包装在钩子 useCallback()
中,如果依赖项数组 service
或 data
包含相同的值,则 returns 相同的函数引用以前的渲染。如果依赖数组中的值发生变化,那么分配给 loadData
的函数将是一个新的函数引用。使用 loadData
作为 useEffect()
挂钩的依赖项允许您重新定义间隔以在 service
或 value
时引用新创建的 loadData
回调变化。下面的可运行示例:
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone@7/babel.min.js"></script>
<script type="text/babel">
const {useState, useEffect, useCallback} = React;
const getRandomAsync = () => new Promise((resolve) => { // simulate api call
setTimeout(resolve, 10, Math.floor(Math.random() * 100));
});
const App = () => {
const [value, setValue] = useState(0);
const loadData = useCallback(async () => {
const num = await getRandomAsync();
console.log("Got random number:", num);
console.log("Value currently is:", value);
setValue(num);
}, [value]);
useEffect(() => {
const timerId = setInterval(loadData, 1000);
return () => clearInterval(timerId);
}, [loadData]);
return <p>{value}</p>;
}
ReactDOM.render(<App />, document.body);
</script>
在useState中使用功能更新:
setValue((prevState) => {
console.log("old value: ", prevState);
return result.data.value;
});
我有一个 useEffect
里面有 setInterval
的功能组件。
但是 loadData
中的值始终等于初始值(0),尽管渲染正确。
如何在 loadData
中获取 setInterval
调用的当前 value
?
...
const [value, setValue] = useState(0);
const [service, setService] = useState();
useEffect(() => {
setService(new ApiService());
}, [])
useEffect(
() => {
const timerId = setInterval(loadData, 1000 * 5);
return () => clearInterval(timerId);
},
[service]
)
async function loadData() {
const result = await service.getData();
console.log("old value: ", value); // "value" is always 0 (initial)
setValue(result.data.value);
}
...
您可以更改 useEffect()
挂钩的依赖项数组,目前由于 loadData
在 value
上关闭,您最终将处于陈旧状态:
const loadData = useCallback(async function() {
const result = await service.getData();
console.log("old value: ", value); // "value" is always 0 (initial)
setValue(result.data.value);
}, [service, value]);
useEffect(() => {
const timerId = setInterval(loadData, 1000 * 5);
return () => clearInterval(timerId);
}, [loadData]);
以上将您的函数包装在钩子 useCallback()
中,如果依赖项数组 service
或 data
包含相同的值,则 returns 相同的函数引用以前的渲染。如果依赖数组中的值发生变化,那么分配给 loadData
的函数将是一个新的函数引用。使用 loadData
作为 useEffect()
挂钩的依赖项允许您重新定义间隔以在 service
或 value
时引用新创建的 loadData
回调变化。下面的可运行示例:
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone@7/babel.min.js"></script>
<script type="text/babel">
const {useState, useEffect, useCallback} = React;
const getRandomAsync = () => new Promise((resolve) => { // simulate api call
setTimeout(resolve, 10, Math.floor(Math.random() * 100));
});
const App = () => {
const [value, setValue] = useState(0);
const loadData = useCallback(async () => {
const num = await getRandomAsync();
console.log("Got random number:", num);
console.log("Value currently is:", value);
setValue(num);
}, [value]);
useEffect(() => {
const timerId = setInterval(loadData, 1000);
return () => clearInterval(timerId);
}, [loadData]);
return <p>{value}</p>;
}
ReactDOM.render(<App />, document.body);
</script>
在useState中使用功能更新:
setValue((prevState) => {
console.log("old value: ", prevState);
return result.data.value;
});