React hooks 引入useState
用于设置组件状态。但是如何使用钩子来替换回调,如下面的代码:
setState(
{ name: "Michael" },
() => console.log(this.state)
);
我想在状态更新后做一些事情。
我知道我可以useEffect
用来做额外的事情,但我必须检查状态以前的值,这需要一些代码。我正在寻找一个可以与useState
钩子一起使用的简单解决方案。
React hooks 引入useState
用于设置组件状态。但是如何使用钩子来替换回调,如下面的代码:
setState(
{ name: "Michael" },
() => console.log(this.state)
);
我想在状态更新后做一些事情。
我知道我可以useEffect
用来做额外的事情,但我必须检查状态以前的值,这需要一些代码。我正在寻找一个可以与useState
钩子一起使用的简单解决方案。
您需要使用useEffect
钩子来实现这一点。
const [counter, setCounter] = useState(0);
const doSomething = () => {
setCounter(123);
}
useEffect(() => {
console.log('Do something after counter has changed', counter);
}, [counter]);
如果你想更新以前的状态,那么你可以在钩子中这样做:
const [count, setCount] = useState(0);
setCount(previousCount => previousCount + 1);
用 模仿setState
回调useEffect
,只触发状态更新(不是初始状态):
const [state, setState] = useState({ name: "Michael" })
const isFirstRender = useRef(true)
useEffect(() => {
if (isFirstRender.current) {
isFirstRender.current = false // toggle flag after first render/mounting
return;
}
console.log(state) // do something after state has updated
}, [state])
useEffectUpdate
function useEffectUpdate(callback) {
const isFirstRender = useRef(true);
useEffect(() => {
if (isFirstRender.current) {
isFirstRender.current = false; // toggle flag after first render/mounting
return;
}
callback(); // performing action after state has updated
}, [callback]);
}
// client usage, given some state dep
const cb = useCallback(() => { console.log(state) }, [state]); // memoize callback
useEffectUpdate(cb);
useEffect
不是一种直观的方式。我为此创建了一个包装器。在这个自定义钩子中,您可以将回调传输到setState
参数而不是useState
参数。
我刚刚创建了 Typescript 版本。因此,如果您需要在 Javascript 中使用它,只需从代码中删除一些类型符号。
const [state, setState] = useStateCallback(1);
setState(2, (n) => {
console.log(n) // 2
});
import { SetStateAction, useCallback, useEffect, useRef, useState } from 'react';
type Callback<T> = (value?: T) => void;
type DispatchWithCallback<T> = (value: T, callback?: Callback<T>) => void;
function useStateCallback<T>(initialState: T | (() => T)): [T, DispatchWithCallback<SetStateAction<T>>] {
const [state, _setState] = useState(initialState);
const callbackRef = useRef<Callback<T>>();
const isFirstCallbackCall = useRef<boolean>(true);
const setState = useCallback((setStateAction: SetStateAction<T>, callback?: Callback<T>): void => {
callbackRef.current = callback;
_setState(setStateAction);
}, []);
useEffect(() => {
if (isFirstCallbackCall.current) {
isFirstCallbackCall.current = false;
return;
}
callbackRef.current?.(state);
}, [state]);
return [state, setState];
}
export default useStateCallback;
如果传递的箭头函数引用了一个变量外部函数,那么它将捕获当前值而不是状态更新后的值。在上面的用法示例中,console.log(state)将打印 1 而不是 2。
我遇到了同样的问题,在我的设置中使用 useEffect 没有解决问题(我正在从多个子组件的数组中更新父级的状态,我需要知道哪个组件更新了数据)。
在 promise 中包装 setState 允许在完成后触发任意操作:
import React, {useState} from 'react'
function App() {
const [count, setCount] = useState(0)
function handleClick(){
Promise.resolve()
.then(() => { setCount(count => count+1)})
.then(() => console.log(count))
}
return (
<button onClick= {handleClick}> Increase counter </button>
)
}
export default App;
以下问题让我找到了正确的方向: React 使用钩子时是否有批处理状态更新功能?