Open into-piece opened 3 years ago
crm是一个多tag页面的SPA项目,打包发布完,用户在没有刷新页面的情况下使用会偶尔出现白屏或一直loading无响应,控制台出现load chunk fail error的报错,分析之后是因为切换页面会发起对对应页面分包代码资源的请求,而当前旧资源已经被清除了。
我引入了ErrorBoundary组件,通过新增的staic getderivedstatefromerror和componentDidcatch生命周期显示备用的样式fallback UI。当我用staic getderivedstatefromerror获取error堆栈信息,设置state中isError为true显示对应友好的报错页面,componentDidcatch进行错误上报,心满意足地觉得毫无破绽的时候,发现其实是没办法捕获到加载分包失败的错误的。
异常捕获是在渲染过程中workloop进行捕获的,而接口报错和事件处理器onClick对应回调内部的js报错则无法捕捉。
这个时候我们可以根据加载分包的loading组件来设置定时,若加载超过一定限制则报错,通过全局状态库保存error值,errorboundry组件获取值进行错误显示,显示替补样式,提醒用户进行刷新。
const [isTimeout, setIsTimeout] = useState(false); useEffect(() => { let timer: NodeJS.Timeout; if (error) { // @ts-ignore clearInterval(timer); } if (!isTimeout) { timer = setTimeout(() => { setIsTimeout(true); }, 4000); } return () => { clearTimeout(timer); }; }, [isTimeout, error]);
但又出现了新问题,我们多tag模式下刷新的话导致其他页面一起刷新,又要重新打开页面录入一堆信息,是你恼火不恼火?那么能不能刷新单个页面吗,重新请求当前页面的分包呢?但是我发现请求失败了如何重新请求分包呢?
我们用的是umi框架,进入源码可以看到代码分割的库是loadable,又是熟悉的老朋友,看一下代码分割实现的源码
umi/packages/runtime/src/dynamic/loadable.js const LoadableComponent = (props, ref) => { init();
umi/packages/runtime/src/dynamic/loadable.js
const LoadableComponent = (props, ref) => { init();
const context = useContext(LoadableContext); const state = useSubscription(subscription); useImperativeHandle(ref, () => ({ retry: subscription.retry, })); if (context && Array.isArray(opts.modules)) { opts.modules.forEach((moduleName) => { context(moduleName); }); } if (state.loading || state.error) { if (process.env.NODE_ENV === 'development' && state.error) { console.error(`[@umijs/runtime] load component failed`, state.error); } return createElement(opts.loading, { isLoading: state.loading, pastDelay: state.pastDelay, timedOut: state.timedOut, error: state.error, retry: subscription.retry, }); } else if (state.loaded) { return opts.render(state.loaded, props); } else { return null; }
};
const LoadableComponentWithRef = forwardRef(LoadableComponent); // add static method in React.forwardRef // https://github.com/facebook/react/issues/17830 LoadableComponentWithRef.preload = () => init(); LoadableComponentWithRef.displayName = 'LoadableComponent';
return LoadableComponentWithRef; }
原来已经暴露了error信息和retry方法,利用retry方法我们可以提供重新刷新当前页面的能力,来重新请求当前分包。
当然我们可以用lazy+suspense进行代码分割,这也是react官方推荐的方法,suspense组件fallback属性,可以设置对应的备用UI
那react中没有两个生命周期组件,我们需要如何捕获项目中的异常呢?sentry的实现方法?
crm是一个多tag页面的SPA项目,打包发布完,用户在没有刷新页面的情况下使用会偶尔出现白屏或一直loading无响应,控制台出现load chunk fail error的报错,分析之后是因为切换页面会发起对对应页面分包代码资源的请求,而当前旧资源已经被清除了。
我引入了ErrorBoundary组件,通过新增的staic getderivedstatefromerror和componentDidcatch生命周期显示备用的样式fallback UI。当我用staic getderivedstatefromerror获取error堆栈信息,设置state中isError为true显示对应友好的报错页面,componentDidcatch进行错误上报,心满意足地觉得毫无破绽的时候,发现其实是没办法捕获到加载分包失败的错误的。
这个时候我们可以根据加载分包的loading组件来设置定时,若加载超过一定限制则报错,通过全局状态库保存error值,errorboundry组件获取值进行错误显示,显示替补样式,提醒用户进行刷新。
但又出现了新问题,我们多tag模式下刷新的话导致其他页面一起刷新,又要重新打开页面录入一堆信息,是你恼火不恼火?那么能不能刷新单个页面吗,重新请求当前页面的分包呢?但是我发现请求失败了如何重新请求分包呢?
我们用的是umi框架,进入源码可以看到代码分割的库是loadable,又是熟悉的老朋友,看一下代码分割实现的源码
};
const LoadableComponentWithRef = forwardRef(LoadableComponent); // add static method in React.forwardRef // https://github.com/facebook/react/issues/17830 LoadableComponentWithRef.preload = () => init(); LoadableComponentWithRef.displayName = 'LoadableComponent';
return LoadableComponentWithRef; }