React钩子引入了useState来设置组件状态。但是我如何使用钩子来替换下面的回调代码:
setState(
{ name: "Michael" },
() => console.log(this.state)
);
我想在状态更新后做一些事情。
我知道我可以使用useEffect来做额外的事情,但我必须检查之前的状态值,这需要位代码。我正在寻找一个简单的解决方案,可以使用useState挂钩。
React钩子引入了useState来设置组件状态。但是我如何使用钩子来替换下面的回调代码:
setState(
{ name: "Michael" },
() => console.log(this.state)
);
我想在状态更新后做一些事情。
我知道我可以使用useEffect来做额外的事情,但我必须检查之前的状态值,这需要位代码。我正在寻找一个简单的解决方案,可以使用useState挂钩。
当前回答
简单的解决方案,只需安装
我使用-state-with-callback
import React from 'react';
import { useStateWithCallbackLazy } from "use-state-with-callback";
const initialFilters = {
smart_filter: "",
};
const MyCallBackComp = () => {
const [filters, setFilters] = useStateWithCallbackLazy(initialFilters);
const filterSearchHandle = (e) => {
setFilters(
{
...filters,
smart_filter: e,
},
(value) => console.log("smartFilters:>", value)
);
};
return (
<Input
type="text"
onChange={(e) => filterSearchHandle(e.target.value)}
name="filter"
placeholder="Search any thing..."
/>
);
};
认为: 反应usestate回调
其他回答
传递一个函数怎么样?
const [name, setName] = useState(initialName);
...
setName(() => {
const nextName = "Michael";
console.log(nextName);
return nextName;
});
我不认为用useRef区分挂载与否是一个好方法,不是一个更好的方法来确定useState()在useEffect()中生成的值是否为初始值?
const [val, setVal] = useState(null)
useEffect(() => {
if (val === null) return
console.log('not mounted, val updated', val)
}, [val])
在我们有内置的setState回调支持之前,我们可以用简单的javascript方式…调用该函数并直接将新变量传递给它。
const [counter, setCounter] = useState(0);
const doSomething = () => {
const newCounter = 123
setCounter(newCounter);
doSomethingWCounter(newCounter);
};
function doSomethingWCounter(newCounter) {
console.log(newCounter); // 123
}
您需要使用useEffect钩子来实现这一点。
const [counter, setCounter] = useState(0);
const doSomething = () => {
setCounter(123);
}
useEffect(() => {
console.log('Do something after counter has changed', counter);
}, [counter]);
如果你想在第一次初始渲染时忽略useEffect回调,那么相应地修改代码:
import React, { useEffect, useRef } from 'react';
const [counter, setCounter] = useState(0);
const didMount = useRef(false);
const doSomething = () => {
setCounter(123);
}
useEffect(() => {
// Return early, if this is the first render:
if ( !didMount.current ) {
return didMount.current = true;
}
// Paste code to be executed on subsequent renders:
console.log('Do something after counter has changed', counter);
}, [counter]);
编辑
在这里使用promise似乎仍然推迟了重新渲染后的执行,两次触发setState可能是获得最新状态的最佳解决方案。因为setState将被列出,我们只需要在重新渲染之前获得prevState。
最初的发布
我刚刚弄清楚了我们是否可以在这里使用一个Promise让setState变成可等待的。
这是我的实验结果,感觉比使用回调更好
主要是在useEffect中触发解析函数
function useAsyncState(initialState) {
const [state, setState] = useState(initialState)
const resolveCb = useRef()
const handleSetState = (updatedState) => new Promise((resolve, reject) => {
// force previous promise resolved
if (typeof resolveCb.current === 'function') {
resolveCb.current(updatedState)
}
resolveCb.current = resolve
try {
setState(updatedState)
} catch(err) {
resolveCb.current = undefined
reject(err)
}
})
useEffect(() => {
if (typeof resolveCb.current === 'function') {
resolveCb.current(state)
resolveCb.current = undefined
}
}, [state])
return [state, handleSetState]
}
组件中使用
function App() {
const [count, setCount] = useAsyncState(0)
const increment = useMemoizedFn(async () => {
const newCount = await setCount(count + 1)
console.log(newCount)
})
console.log('rerender')
return (
<div>
<h3 onClick={increment}>Hi, {count}</h3>
</div>
)
}