React Native中如何实现文本懒加载?解决页面卡顿问题
React Native 大文本单词动态样式优化方案
原代码问题分析
你之前用lazy和Suspense的方式完全错误:lazy是用来异步加载组件模块的,不是直接生成元素列表的工具。而且给400个单词每个套一层View+Text,会瞬间创建数百个组件实例,这才是卡顿的核心原因。
可行解决方案
方案1:异步分批渲染,先显示原始文本
核心思路是先渲染无样式的完整文本占位,然后在后台分批处理单词,逐步替换成带样式的可点击元素,避免一次性渲染大量组件阻塞UI。
import React, { useState, useEffect } from 'react'; import { Text, View, StyleSheet, TouchableOpacity } from 'react-native'; import Constants from 'expo-constants'; const str = 'pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh mauris cursus mattis molestie a iaculis at erat pellentesque adipiscing commodo elit at imperdiet dui accumsan sit amet nulla facilisi morbi tempus iaculis urna id volutpat lacus laoreet non curabitur gravida arcu ac tortor dignissim convallis aenean et tortor at risus viverra adipiscing at in tellus integer feugiat scelerisque varius morbi enim nunc faucibus a pellentesque sit amet porttitor eget dolor morbi non arcu risus quis varius quam quisque id diam vel quam elementum pulvinar etiam non quam lacus suspendisse faucibus interdum posuere lorem ipsum dolor sit amet consectetur adipiscing elit duis tristique sollicitudin nibh sit amet commodo nulla facilisi nullam vehicula ipsum a arcu cursus vitae congue mauris rhoncus aenean vel elit scelerisque mauris pellentesque pulvinar'; const words = str.split(' '); const BATCH_SIZE = 20; // 每次渲染20个单词,可根据设备性能调整 export default function App() { const [renderedWords, setRenderedWords] = useState([]); const [currentIndex, setCurrentIndex] = useState(0); const [showRawText, setShowRawText] = useState(true); // 标记是否显示原始文本 useEffect(() => { const processBatch = () => { const endIndex = Math.min(currentIndex + BATCH_SIZE, words.length); // 生成当前批次的可点击单词元素 const newBatch = words.slice(currentIndex, endIndex).map((word, idx) => ( <TouchableOpacity key={`word-${currentIndex + idx}`} style={styles.styledWord} onPress={() => console.log('点击单词:', word)} > <Text style={styles.styledWordText}>{word}</Text> </TouchableOpacity> )); setRenderedWords(prev => [...prev, ...newBatch]); setCurrentIndex(endIndex); // 所有单词处理完成后隐藏原始文本 if (endIndex >= words.length) { setShowRawText(false); } }; // 用requestAnimationFrame让渲染在UI空闲时执行,避免阻塞 const timer = setTimeout(() => { requestAnimationFrame(processBatch); }, 0); if (currentIndex < words.length) { return () => clearTimeout(timer); } }, [currentIndex]); return ( <View style={styles.container}> {/* 原始文本先占位,处理完成后被覆盖 */} {showRawText && <Text style={styles.paragraph}>{str}</Text>} <View style={styles.wordContainer}> {renderedWords.map((wordEl, idx) => ( <> {wordEl} {/* 单词之间加空格 */} {idx !== renderedWords.length - 1 && <Text> </Text>} </> ))} </View> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', paddingTop: Constants.statusBarHeight, backgroundColor: '#ecf0f1', padding: 8, }, paragraph: { margin: 24, fontSize: 18, position: 'absolute', top: Constants.statusBarHeight + 8, left: 8, right: 8, }, wordContainer: { margin: 24, flexWrap: 'wrap', flexDirection: 'row', }, styledWord: { borderRadius: 8, backgroundColor: 'pink', marginHorizontal: 2, paddingHorizontal: 4, }, styledWordText: { fontSize: 18, }, });
方案2:优化组件结构,用嵌套Text替代View+Text
React Native的Text组件支持嵌套,直接在父Text里嵌套带样式的Text,比用View包装性能高很多——因为View会创建额外的原生视图节点,增加渲染开销。
import React, { useState, useEffect } from 'react'; import { Text, View, StyleSheet, TouchableWithoutFeedback } from 'react-native'; import Constants from 'expo-constants'; const str = 'pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh mauris cursus mattis molestie a iaculis at erat pellentesque adipiscing commodo elit at imperdiet dui accumsan sit amet nulla facilisi morbi tempus iaculis urna id volutpat lacus laoreet non curabitur gravida arcu ac tortor dignissim convallis aenean et tortor at risus viverra adipiscing at in tellus integer feugiat scelerisque varius morbi enim nunc faucibus a pellentesque sit amet porttitor eget dolor morbi non arcu risus quis varius quam quisque id diam vel quam elementum pulvinar etiam non quam lacus suspendisse faucibus interdum posuere lorem ipsum dolor sit amet consectetur adipiscing elit duis tristique sollicitudin nibh sit amet commodo nulla facilisi nullam vehicula ipsum a arcu cursus vitae congue mauris rhoncus aenean vel elit scelerisque mauris pellentesque pulvinar'; const words = str.split(' '); export default function App() { const [processedText, setProcessedText] = useState(null); useEffect(() => { // 异步处理文本,避免阻塞初始渲染 setTimeout(() => { const elements = words.map((word, idx) => ( <TouchableWithoutFeedback key={idx} onPress={() => console.log('点击:', word)}> <Text style={styles.styledWord}> {word} {idx !== words.length - 1 ? ' ' : ''} </Text> </TouchableWithoutFeedback> )); setProcessedText(elements); }, 0); }, []); return ( <View style={styles.container}> <Text style={styles.paragraph}> {/* 先显示原始文本,处理完成后替换为带样式的元素 */} {processedText || str} </Text> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', paddingTop: Constants.statusBarHeight, backgroundColor: '#ecf0f1', padding: 8, }, paragraph: { margin: 24, fontSize: 18, }, styledWord: { borderRadius: 8, backgroundColor: 'pink', paddingHorizontal: 4, }, });
关键优化点
- 避免一次性渲染数百个组件:分批渲染或者使用更轻量的组件结构
- 用
requestAnimationFrame或setTimeout把耗时操作放到UI空闲时执行 - 优先用
Text嵌套替代View+Text,减少原生视图节点数量
内容的提问来源于stack exchange,提问作者DingleberrySmith
相关产品推荐
相关产品推荐

