reactjs - 响应自定义挂钩以记录页面渲染开始事件
问题描述
我正在为一个用于性能监控的 react js 应用程序编写一个日志框架。基本上,sdk 提供了两种方法来创建时间事件,并停止测量并将时间细节推送到它想要的任何地方。由于我也需要捕获数据获取部分,所以我想将创建的计时事件存储在 redux 存储中,以便稍后在获取数据时停止计时器。为了尽可能多地将视图组件与日志记录分离,我正在尝试编写两个自定义挂钩以用于以下目的。
- 如果具有给定键的状态中没有可用的内容,则创建计时事件并将其存储在状态中
- 通过提供的键在存储中查找计时事件并停止计时器
以下是我创建的钩子。
export const useStartRenderLogger = (
component: string,
key: string,
eventParams?: any
): void => {
const dispatch = useDispatch();
const existingTimer = useGetTimerByKey(key); <= Selector which return timer for key
const metrics = useMetrics(component); <= sdk hook to create a metric instance
if (existingTimer) return;
const timer = metrics.start(key, {
...eventParams,
stage: TimeLogStages.Render,
});
dispatch(TimeLogActions.pushLogger(key, timer)); <= dispatch passing timing log and key so it can stored on state
};
export const useStopRenderLogger = (
key: string,
pageRendered: boolean,
params?: any
): void => {
const timer = useGetTimerByKey(key);
const dispatch = useDispatch();
if (!pageRendered || isUndefined(timer)) return;
timer.stop(params);
dispatch(TimeLogActions.popLogger(key));
};
我在组件的开头调用第一个,在渲染传递布尔值之前调用另一个,以指示是否已获取数据。
问题是useStartRenderLogger
抛出与钩子的反应规则相关的错误。
index.js:1 Warning: React has detected a change in the order of Hooks called by MyComponent. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks
看来调度正在解决问题。我猜想将事件推入状态使useGetTimerByKey
选择器更新并导致错误。如果该行被注释,则页面呈现没有错误。
我关于为什么抛出错误的假设是正确的吗?我可以让useGetTimeByKey
选择器在状态改变时不更新吗?
解决方案
问题:return
上钩之前
问题是这两行:
if (existingTimer) return;
const metrics = useMetrics(component);
您必须在每次渲染时以相同的顺序调用相同的钩子。调用钩子不能是有条件的。所以你不能return
在你的代码中有一个以上的钩子调用,因为这意味着useMetrics
有时会被调用。
如果你想有一些条件逻辑,你可以把它移到useMetrics
钩子里面。
可以使纯函数有条件。调用dispatch(action)
可以是有条件的——但调用useDispatch
不能。所以这段代码没问题:
export const useStartRenderLogger = (
component: string,
key: string,
eventParams?: any
): void => {
// call all hooks first
const dispatch = useDispatch();
const existingTimer = useGetTimerByKey(key);
const metrics = useMetrics(component);
// only return after all hooks are called
if (existingTimer) return;
// conditionally executed
const timer = metrics.start(key, {
...eventParams,
stage: TimeLogStages.Render,
});
dispatch(TimeLogActions.pushLogger(key, timer));
};
推荐阅读
- javascript - 文档数组内的猫鼬更新地图元素
- ios - 向多个应用发送推送通知
- ruby - 比较浮点数的随机 RSpec 失败(Eq 匹配器)
- excel - 在excel VBA中以偶数换行符分隔的字符串前面插入一些东西,在奇数换行符分隔的字符串前面插入其他东西
- kotlin-coroutines - 我什么时候应该使用 `Dispatchers.Unconfined` 和 `EmptyCoroutineContext`?
- sidekiq - Sidekiq 父批次不等待子批次
- amazon-web-services - 403 访问被拒绝消息 - EC2 - Tomcat8
- django - Django 在一页上管理多个查询集
- java - 在 Java 中收集 Trie 中的所有单词
- gensim - 我可以通过同时推断所有文档来为要推断的每个文档保留 doc2vec 模式的随机状态吗?