react-native - 如果我在函数中间更新状态,函数其余部分的执行顺序是什么?
问题描述
我正在使用 Context API 和带有钩子的 React 功能组件。我有一个功能组件 ProfileForm.js
在这个文件的顶部,我调用了 useContext以便我可以访问当前状态(一组配置文件对象)。
const {state: {userProfiles}, addProfile, removeProfile, editProfile} = useContext(UserProfilesContext);
对于这个例子,我将重点关注函数addProfile
。当用户单击提交按钮时,我想将新配置文件添加到全局状态/上下文中,并且我想将更新后的列表保存到AsyncStorage
.
这是我的处理程序:
const saveProfileHandler = async(profiles) = >
{
const {
firstName, lastName, userPhone, userEmail, userMonth, userDay, userYear,
userStreet, userCity, userState, userZip,
}
= formState.inputValues;
Keyboard.dismiss();
if (validateForm()) {
let month = userMonth;
let day = userDay;
if (month.length == = 1) {
month = `0 $ { userMonth }
`;
}
if (day.length == = 1) {
day = `0 $ { userDay }
`;
}
const profile = new UserProfile(
firstName.trim(),
lastName.trim(),
userPhone.trim(),
userEmail.trim(),
month.trim(),
day.trim(),
userYear.trim(),
userStreet.trim(),
userCity.trim(),
userState.trim(),
userZip.trim(), );
// add profile to Context object
addProfile(profile);
await saveUserProfilesToStorage([... profiles, profile ]);
navigation.pop();
}
};
当我调用时,addProfile
我会更新全局状态/上下文,所以我知道 React 会重新渲染我的组件。所以,我真的有两个问题:
- 依赖我刚刚保存的全局状态值是否不安全。我的意思是,我可以使用更新的上下文状态并将其保存到 AsyncStorage 还是它还没有更新,因此不可靠?
- 在我调用之后
addProfile
,函数的其余部分是否会在从状态更新重新渲染之前继续运行,或者是否addProfile
会导致组件在函数的其余部分完成之前重新渲染?如果它确实在函数调用中间重新渲染,那么函数的其余部分何时执行?
提前致谢。
解决方案
这是我能够学到的。我会把它放在这里给其他偶然发现它的人。
重要的是要知道在 React 中,setState() 是一个异步函数。JavaScript 引擎由内存堆和调用栈组成。调用堆栈将运行所有同步函数。除了 JavaScript 引擎之外,还有 Web API(由浏览器提供)和事件循环(回调队列)。
当一个函数被执行时,它被放置在调用栈中并且同步开始执行。如果您从当前正在运行的函数内部调用另一个函数,则新函数将获得自己的执行上下文。当前函数将暂停执行,新函数将执行完成(假设在其上下文中没有新函数调用)并将控制权返回给将继续执行的第一个函数。
异步事件
异步代码在浏览器的 Web API 环境中运行。这可以防止代码阻塞 JavaScript 线程/调用堆栈。异步代码的回调函数在 Web API 环境中注册。当回调准备好执行时,它被放置在回调队列中。所有的回调,除了那些由 promise 返回的,都在这里排队。
在调用堆栈为空之前,不会执行回调。然后它们将按 FIFO(先进先出)顺序执行。
同样重要的是要知道来自 Promise 的回调(然后是 catch)不会被放入回调队列中。他们进入一个微任务队列。此队列优先于回调队列。这意味着微任务队列中的所有回调都将在回调队列的任务之前被调用。
就我而言,上下文更新将在之后发生,navigation.pop();
但由于上下文是全局的,并且在组件卸载后我不会更新 UI,所以应该没问题。
如果我有什么不对的地方欢迎指正。
推荐阅读
- swiper - 如何在 SwiperJS 容器外使用分页?
- database-project - 执行 DACPAC 文件时出错(使用 sqlpackage.exe)
- java - java反向三角形星形图案
- ios - 为所有 UIViewController 实例设置全局默认后退按钮显示模式
- git - git:将子模块分支重置为远程标签
- javascript - 如何期望记录器同时抛出错误并通过单元测试?
- python-3.x - 未显示 Voila 的 Ipywidgets:错误龙卷风未捕获异常 GET
- javascript - 如何在循环JS中仅触发一个按钮
- javascript - 条件与结果不符
- azure-data-factory-2 - 是否可以在 Azure 数据工厂中使用 MD5 哈希编码重命名文件名?