过去,我写的 reactjs 代码是这样的:
class App extends Component {
state = { var1:null, var2:null, var3:null };
myfunction1 = async () => {
...
this.setState({ var1:10, var2:20, var3:30 }, this.myfunction2);
}
myfunction2 = async () => {
...
};
render() {
console.log("render");
return (
<div className="App">
{ this.state.var1 }
{ this.state.var2 }
{ this.state.var3 }
</div>
);
}
现在,我是这样工作的:
const App = () => {
const [var1, setVar1] = useState(null);
const [var2, setVar2] = useState(null);
const [var3, setVar3] = useState(null);
async function init() {
setVar1(10);
setVar2(20);
setVar3(30);
function2();
}
useEffect(() => { init(); }, []);
async function function2() {
}
console.log("render");
return (
<div className="App">
{ var1 }
{ var2 }
{ var3 }
</div>
);
这是我在第二种方式中的问题:
有没有办法在同一个调用中设置 setVar1、setVar2 和 setVar3?问题是页面将刷新 3 次。在第一次刷新时,var1 将等于 10,但 var2 和 var3 将为空。它可能会导致一些问题...
我如何确定在设置 var1、var2 和 var3 之后会调用 function2?在第一种方法中有一个回调函数,只有在设置状态时才会调用它。我如何在第二种方法中做同样的事情?
谢谢
答案 0 :(得分:2)
请注意,您的两个示例不等价,您需要有一个状态对象,这样它们才会是。
<块引用>有没有办法在同一个调用中设置 setVar1、setVar2 和 setVar3?
您实际上是在问 how to batch state changes,React 不会像您 (async
) 那样批量承诺调用。
要么将 promise 调用更改为普通调用,要么尝试使用单个状态对象等通用解决方案。
useState({ var1: null, var2: null, var3: null })
<块引用>
我如何确定 function2 会在 init
之后被调用
您正在使用异步调用,因此只需在第一个调用解决后调用 function2
。或者,您可以使用布尔值引用来指示您在 init
调用,similar logic on having useEffect
stop running after mount 之后。
完整示例:
const App = () => {
const [state, setState] = useState({ var1: null, var2: null, var3: null });
// or
const isInitCalled = useRef(false);
function function2() {
console.log("after");
}
useEffect(async () => {
async function init() {
setVar1({ var1: 10, var2: 20, var3: 30 });
function2();
}
await init();
function2();
}, []);
// Or
useEffect(() => {
init();
isInitCalled.current = true;
}, []);
useEffect(() => {
if (isInitCalled.current) {
func2();
}
}, [state]);
return (
<div className="App">
{var1}
{var2}
{var3}
</div>
);
};
答案 1 :(得分:0)
您可以使用数组或对象代替原始值:
const App = () => {
const [vars, setVars] = useState([null, null, null]);
async function init() {
setVars([10, 20, 30]);
function2();
}
useEffect(() => { init(); }, []);
async function function2() {
}
console.log("render");
return (
<div className="App">
{ vars[0] }
{ vars[1] }
{ vars[2] }
</div>
);
当然,如果您的实际“变量”没有编号,您可能更喜欢带有属性的对象而不是数组。
答案 2 :(得分:0)
有没有办法在同一个调用中设置 setVar1、setVar2 和 setVar3?问题是页面将刷新 3 次。在第一次刷新时,var1 将等于 10,但 var2 和 var3 将为空。它可能会导致一些问题...
首先,我只想指出它不一定要渲染多次。如果代码在 react 中开始执行(例如,useEffect
或合成事件),那么 react 将批量处理多个状态更改并且只执行一次重新渲染。但是确实在某些情况下,react 并没有开始执行,所以执行不会返回到react,所以react 只能立即重新渲染。例如,如果您在 setTimeout
回调中或在 await
承诺之后设置状态,就会发生这种情况。
如果只需要一次重新渲染就需要多次设置状态,可以使用unstable_batchedUpdates
。
import { unstable_batchedUpdates } from 'react';
// ...
async function init() {
unstable_batchedUpdates(() => {
setVar1(10);
setVar2(20);
setVar3(30);
})
function2();
}
术语“不稳定”是 React 团队的说法,这个 api 可能会在 React 的下一个主要版本中发生变化。但是使用起来是完全安全的,只要你在升级 React 版本时注意这一点。
<块引用>我如何确定在设置 var1、var2 和 var3 之后会调用 function2?在第一种方法中有一个回调函数,只有在设置状态时才会调用它。我如何在第二种方法中做同样的事情?
在功能组件中设置状态并不能知道组件何时重新渲染。这可能是因为它不会有任何好处。没有发生变异的 this
,因此无论经过多少时间,function2 都不会看到新值。它的闭包中包含来自当前渲染的值,并且无法访问下一个渲染。
相反,修复最有可能将新值传递给 function2。例如,如果它需要知道 var1 变为 10,则需要将其传递给 10。
async function init() {
const newVar1 = 10;
unstable_batchedUpdates(() => {
setVar1(newVar1);
setVar2(20);
setVar3(30);
})
function2(newVar1);
}
async function function2(newVar1) {
}