UNPKG

@mpxjs/webpack-plugin

Version:

mpx compile core

146 lines (145 loc) 5 kB
import { useState, useEffect, useCallback, useRef, createElement } from 'react'; import { View, Image, StyleSheet, Text, TouchableOpacity } from 'react-native'; import FastImage from '@d11/react-native-fast-image'; const asyncChunkMap = new Map(); const styles = StyleSheet.create({ container: { flex: 1, padding: 20, backgroundColor: '#fff' }, loadingImage: { width: 100, height: 100, marginTop: 220, alignSelf: 'center' }, buttonText: { color: '#fff', fontSize: 16, fontWeight: '500', textAlign: 'center' }, errorImage: { marginTop: 80, width: 220, aspectRatio: 1, alignSelf: 'center' }, errorText: { fontSize: 16, textAlign: 'center', color: '#333', marginBottom: 20 }, retryButton: { position: 'absolute', bottom: 54, left: 20, right: 20, backgroundColor: '#fff', paddingVertical: 15, borderRadius: 30, marginTop: 40, borderWidth: 1, borderColor: '#FF5F00' }, retryButtonText: { color: '#FF5F00', fontSize: 16, fontWeight: '500', textAlign: 'center' } }); const DefaultFallback = ({ onReload }) => { return (<View style={styles.container}> <Image source={{ uri: 'https://dpubstatic.udache.com/static/dpubimg/Vak5mZvezPpKV5ZJI6P9b_drn-fallbak.png' }} style={styles.errorImage} resizeMode="contain"/> <Text style={styles.errorText}>网络出了点问题,请查看网络环境</Text> <TouchableOpacity style={styles.retryButton} onPress={onReload} activeOpacity={0.7}> <Text style={styles.retryButtonText}>点击重试</Text> </TouchableOpacity> </View>); }; const DefaultLoading = () => { return (<View style={styles.container}> <FastImage style={styles.loadingImage} source={{ uri: 'https://dpubstatic.udache.com/static/dpubimg/439jiCVOtNOnEv9F2LaDs_loading.gif' }} resizeMode={FastImage.resizeMode.contain}></FastImage> </View>); }; const AsyncSuspense = ({ type, chunkName, moduleId, innerProps, getLoading, getFallback, getChildren }) => { const [status, setStatus] = useState('pending'); const chunkLoaded = asyncChunkMap.has(moduleId); const loadChunkPromise = useRef(null); const reloadPage = useCallback(() => { setStatus('pending'); }, []); useEffect(() => { let cancelled = false; if (!chunkLoaded && status === 'pending') { if (loadChunkPromise.current) { loadChunkPromise .current.then((res) => { if (cancelled) return; asyncChunkMap.set(moduleId, res); setStatus('loaded'); }) .catch((e) => { if (cancelled) return; if (type === 'component') { global.__mpxAppCbs.lazyLoad.forEach((cb) => { // eslint-disable-next-line node/no-callback-literal cb({ type: 'subpackage', subpackage: [chunkName], errMsg: `loadSubpackage: ${e.type}` }); }); } if (type === 'page' && typeof mpxGlobal.__mpx.config?.rnConfig?.lazyLoadPageErrorHandler === 'function') { mpxGlobal.__mpx.config.rnConfig.lazyLoadPageErrorHandler({ subpackage: chunkName, errType: e.type }); } loadChunkPromise.current = null; setStatus('error'); }); } } return () => { cancelled = true; }; }, [status]); if (chunkLoaded) { const Comp = asyncChunkMap.get(moduleId); return createElement(Comp, innerProps); } else if (status === 'error') { if (type === 'page') { const fallback = getFallback ? getFallback() : DefaultFallback; return createElement(fallback, { onReload: reloadPage }); } else { return getFallback ? createElement(getFallback(), innerProps) : null; } } else { if (!loadChunkPromise.current) { loadChunkPromise.current = getChildren(); } if (type === 'page') { const loading = getLoading ? getLoading() : DefaultLoading; return createElement(loading); } else { return getFallback ? createElement(getFallback(), innerProps) : null; } } }; AsyncSuspense.displayName = 'MpxAsyncSuspense'; export default AsyncSuspense;