React钩子引入了useState来设置组件状态。但是我如何使用钩子来替换下面的回调代码:
setState(
{ name: "Michael" },
() => console.log(this.state)
);
我想在状态更新后做一些事情。
我知道我可以使用useEffect来做额外的事情,但我必须检查之前的状态值,这需要位代码。我正在寻找一个简单的解决方案,可以使用useState挂钩。
React钩子引入了useState来设置组件状态。但是我如何使用钩子来替换下面的回调代码:
setState(
{ name: "Michael" },
() => console.log(this.state)
);
我想在状态更新后做一些事情。
我知道我可以使用useEffect来做额外的事情,但我必须检查之前的状态值,这需要位代码。我正在寻找一个简单的解决方案,可以使用useState挂钩。
当前回答
在我们有内置的setState回调支持之前,我们可以用简单的javascript方式…调用该函数并直接将新变量传递给它。
const [counter, setCounter] = useState(0);
const doSomething = () => {
const newCounter = 123
setCounter(newCounter);
doSomethingWCounter(newCounter);
};
function doSomethingWCounter(newCounter) {
console.log(newCounter); // 123
}
其他回答
你可以使用以下方法,我知道获得更新后的最新状态:
useEffect https://reactjs.org/docs/hooks-reference.html#useeffect
const [state, setState] = useState({name: "Michael"});
const handleChangeName = () => {
setState({name: "Jack"});
}
useEffect(() => {
console.log(state.name); //"Jack"
//do something here
}, [state]);
功能更新 https://reactjs.org/docs/hooks-reference.html#functional-updates 如果新的状态是用之前的状态计算出来的,你可以传递一个函数给setState。该函数将接收之前的值,并返回更新后的值。”
const [state, setState] = useState({name: "Michael"});
const handleChangeName = () => {
setState({name: "Jack"})
setState(prevState => {
console.log(prevState.name);//"Jack"
//do something here
// return updated state
return prevState;
});
}
useRef https://reactjs.org/docs/hooks-reference.html#useref 返回的ref对象将在组件的整个生命周期内持续存在。
const [state, setState] = useState({name: "Michael"});
const stateRef = useRef(state);
stateRef.current = state;
const handleClick = () => {
setState({name: "Jack"});
setTimeout(() => {
//it refers to old state object
console.log(state.name);// "Michael";
//out of syntheticEvent and after batch update
console.log(stateRef.current.name);//"Jack"
//do something here
}, 0);
}
在react synticevent处理程序中,setState是一个批量更新过程,因此每次状态更改都会等待并返回一个新状态。 setState()并不总是立即更新组件。它可以批处理或延迟更新。", https://reactjs.org/docs/react-component.html#setstate
这里有一个有用的链接 React是否保持状态更新的顺序?
我不认为用useRef区分挂载与否是一个好方法,不是一个更好的方法来确定useState()在useEffect()中生成的值是否为初始值?
const [val, setVal] = useState(null)
useEffect(() => {
if (val === null) return
console.log('not mounted, val updated', val)
}, [val])
您需要使用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]);
我们可以写一个叫做useScheduleNextRenderCallback的钩子,它返回一个“schedule”函数。在我们调用setState之后,我们可以调用“schedule”函数,传递一个我们希望在下次呈现时运行的回调。
import { useCallback, useEffect, useRef } from "react";
type ScheduledCallback = () => void;
export const useScheduleNextRenderCallback = () => {
const ref = useRef<ScheduledCallback>();
useEffect(() => {
if (ref.current !== undefined) {
ref.current();
ref.current = undefined;
}
});
const schedule = useCallback((fn: ScheduledCallback) => {
ref.current = fn;
}, []);
return schedule;
};
使用示例:
const App = () => {
const scheduleNextRenderCallback = useScheduleNextRenderCallback();
const [state, setState] = useState(0);
const onClick = useCallback(() => {
setState(state => state + 1);
scheduleNextRenderCallback(() => {
console.log("next render");
});
}, []);
return <button onClick={onClick}>click me to update state</button>;
};
简化的测试用例:https://stackblitz.com/edit/react-ts-rjd9jk
我认为你需要的是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;