React钩子引入了useState来设置组件状态。但是我如何使用钩子来替换下面的回调代码:
setState(
{ name: "Michael" },
() => console.log(this.state)
);
我想在状态更新后做一些事情。
我知道我可以使用useEffect来做额外的事情,但我必须检查之前的状态值,这需要位代码。我正在寻找一个简单的解决方案,可以使用useState挂钩。
React钩子引入了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]);
如果你想在第一次初始渲染时忽略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]);
其他回答
我有一个用例,我想做一个api调用与一些参数后的状态设置。我不想设置这些参数作为我的状态,所以我做了一个自定义钩子,这是我的解决方案
import { useState, useCallback, useRef, useEffect } from 'react';
import _isFunction from 'lodash/isFunction';
import _noop from 'lodash/noop';
export const useStateWithCallback = initialState => {
const [state, setState] = useState(initialState);
const callbackRef = useRef(_noop);
const handleStateChange = useCallback((updatedState, callback) => {
setState(updatedState);
if (_isFunction(callback)) callbackRef.current = callback;
}, []);
useEffect(() => {
callbackRef.current();
callbackRef.current = _noop; // to clear the callback after it is executed
}, [state]);
return [state, handleStateChange];
};
用useEffect模拟setState回调,只在状态更新时触发(不是初始状态):
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);
在我们有内置的setState回调支持之前,我们可以用简单的javascript方式…调用该函数并直接将新变量传递给它。
const [counter, setCounter] = useState(0);
const doSomething = () => {
const newCounter = 123
setCounter(newCounter);
doSomethingWCounter(newCounter);
};
function doSomethingWCounter(newCounter) {
console.log(newCounter); // 123
}
我不认为用useRef区分挂载与否是一个好方法,不是一个更好的方法来确定useState()在useEffect()中生成的值是否为初始值?
const [val, setVal] = useState(null)
useEffect(() => {
if (val === null) return
console.log('not mounted, val updated', val)
}, [val])
我认为你需要的是useState和useCallback:
useState react doc; useCallback react doc;
示例代码
import React, { useCallback, useState } from 'react';
const Test = () => {
const [name, setName] = useState("");
const testCallback = useCallback(() => console.log(name), [name]);
return (
<button onClick={() => {
setName("Michael")
testCallback();
}}>Name</button>
)
};
export default Test;