feat: 修复动态 reducer 注入导致的运行时错误
This commit is contained in:
10
src/App.js
10
src/App.js
@@ -114,6 +114,16 @@ function AppContent() {
|
||||
|
||||
// 初始化 PostHog
|
||||
dispatch(posthogSliceModule.initializePostHog());
|
||||
|
||||
// ⚡ 刷新注入前缓存的事件(避免丢失)
|
||||
const pendingEvents = posthogSliceModule.flushPendingEventsBeforeInjection();
|
||||
if (pendingEvents.length > 0) {
|
||||
logger.info('App', `刷新 ${pendingEvents.length} 个注入前缓存的事件`);
|
||||
pendingEvents.forEach(({ eventName, properties }) => {
|
||||
posthogModule.trackEventAsync(eventName, properties);
|
||||
});
|
||||
}
|
||||
|
||||
logger.info('App', 'PostHog 模块空闲时加载完成,Redux 初始化已触发');
|
||||
} catch (error) {
|
||||
logger.error('App', 'PostHog 加载失败', error);
|
||||
|
||||
@@ -12,6 +12,19 @@ import {
|
||||
} from '../../lib/posthog';
|
||||
import { logger } from '../../utils/logger';
|
||||
|
||||
// ⚡ 模块级缓存:存储 reducer 注入前的事件(避免丢失)
|
||||
let pendingEventsBeforeInjection = [];
|
||||
|
||||
/**
|
||||
* 获取并清空注入前缓存的事件
|
||||
* 在 App.js 中 reducer 注入后调用
|
||||
*/
|
||||
export const flushPendingEventsBeforeInjection = () => {
|
||||
const events = [...pendingEventsBeforeInjection];
|
||||
pendingEventsBeforeInjection = [];
|
||||
return events;
|
||||
};
|
||||
|
||||
// ==================== Initial State ====================
|
||||
|
||||
const initialState = {
|
||||
@@ -51,7 +64,15 @@ export const initializePostHog = createAsyncThunk(
|
||||
'posthog/initialize',
|
||||
async (_, { getState, rejectWithValue }) => {
|
||||
try {
|
||||
const { config } = getState().posthog;
|
||||
const posthogState = getState().posthog;
|
||||
|
||||
// ⚡ 防御性检查:reducer 尚未注入
|
||||
if (!posthogState) {
|
||||
logger.warn('PostHog', 'PostHog reducer 尚未注入,跳过初始化');
|
||||
return { isInitialized: false, skipped: true };
|
||||
}
|
||||
|
||||
const { config } = posthogState;
|
||||
|
||||
if (!config.apiKey) {
|
||||
logger.warn('PostHog', '未配置 API Key,分析功能将被禁用');
|
||||
@@ -112,7 +133,20 @@ export const trackEvent = createAsyncThunk(
|
||||
'posthog/trackEvent',
|
||||
async ({ eventName, properties = {} }, { getState, rejectWithValue }) => {
|
||||
try {
|
||||
const { isInitialized } = getState().posthog;
|
||||
const posthogState = getState().posthog;
|
||||
|
||||
// ⚡ reducer 尚未注入:缓存到模块级队列(不丢弃)
|
||||
if (!posthogState) {
|
||||
logger.debug('PostHog', 'PostHog reducer 尚未注入,事件已缓存', { eventName });
|
||||
pendingEventsBeforeInjection.push({
|
||||
eventName,
|
||||
properties,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
return { eventName, properties, pendingInjection: true };
|
||||
}
|
||||
|
||||
const { isInitialized } = posthogState;
|
||||
|
||||
if (!isInitialized) {
|
||||
logger.warn('PostHog', 'PostHog 未初始化,事件将被缓存', { eventName });
|
||||
@@ -160,7 +194,14 @@ export const flushCachedEvents = createAsyncThunk(
|
||||
'posthog/flushCachedEvents',
|
||||
async (_, { getState, dispatch }) => {
|
||||
try {
|
||||
const { eventQueue, isInitialized } = getState().posthog;
|
||||
const posthogState = getState().posthog;
|
||||
|
||||
// ⚡ 防御性检查:reducer 尚未注入
|
||||
if (!posthogState) {
|
||||
return { flushed: 0, skipped: true };
|
||||
}
|
||||
|
||||
const { eventQueue, isInitialized } = posthogState;
|
||||
|
||||
if (!isInitialized || eventQueue.length === 0) {
|
||||
return { flushed: 0 };
|
||||
@@ -281,15 +322,16 @@ export const {
|
||||
|
||||
// ==================== Selectors ====================
|
||||
|
||||
export const selectPostHog = (state) => state.posthog;
|
||||
export const selectIsInitialized = (state) => state.posthog.isInitialized;
|
||||
export const selectUser = (state) => state.posthog.user;
|
||||
export const selectFeatureFlags = (state) => state.posthog.featureFlags;
|
||||
export const selectEventQueue = (state) => state.posthog.eventQueue;
|
||||
export const selectStats = (state) => state.posthog.stats;
|
||||
// ⚡ 安全的 selectors(支持 reducer 未注入的情况)
|
||||
export const selectPostHog = (state) => state.posthog || initialState;
|
||||
export const selectIsInitialized = (state) => state.posthog?.isInitialized ?? false;
|
||||
export const selectUser = (state) => state.posthog?.user ?? null;
|
||||
export const selectFeatureFlags = (state) => state.posthog?.featureFlags ?? {};
|
||||
export const selectEventQueue = (state) => state.posthog?.eventQueue ?? [];
|
||||
export const selectStats = (state) => state.posthog?.stats ?? initialState.stats;
|
||||
|
||||
export const selectFeatureFlag = (flagKey) => (state) => {
|
||||
return state.posthog.featureFlags[flagKey] || posthogGetFeatureFlag(flagKey);
|
||||
return state.posthog?.featureFlags?.[flagKey] || posthogGetFeatureFlag(flagKey);
|
||||
};
|
||||
|
||||
export const selectIsOptedOut = () => posthogHasOptedOut();
|
||||
|
||||
Reference in New Issue
Block a user