如何基于指定参数仅重渲染React Native中的目标组件?
优化React Native单词高亮渲染性能问题
问题描述
我正在开发一个功能:遍历文本并根据状态为每个单词单独设置样式。当用户点击某个单词时,希望页面上该单词的所有实例重新渲染并应用不同样式,但当前实现会重新渲染全部文本,导致应用严重卡顿。
请问是否可以通过向每个组件传递参数来重新设置映射组件的样式,或者为每个单词创建memo来优化?
示例代码
RenderedText组件
import React, {useState} from 'react'; import { Text, View, StyleSheet} from 'react-native'; export default function RenderedText() { const [yellowHighlightedWords, setYellowHighlightedWords] = useState(["west", "where", "neighborhood", "trouble", "cool"]) const [redHighlightedWords, setRedHighlightedWords] = useState(["playground", "school", "most"]) const str = "In West Philadelphia born and raised, On the playground is where I spent most of my days Chillin' out, maxin', relaxin' all cool And all shootin' some b-ball outside of the school When a couple of guys who were up to no good Started makin' trouble in my neighborhood I got in one little fight and my mom got scared" let arr = str.split(/\s/g) const handlePress = (el) => { let word = el.toLowerCase() if (yellowHighlightedWords.includes(word) === true) { setYellowHighlightedWords((prevState) => { return prevState.filter(element => { return element !== word }) }) } else if (redHighlightedWords.includes(word) === true) { setRedHighlightedWords((prevState) => { return prevState.filter(element => { return element !== word }) }) } else { setYellowHighlightedWords((prevState) => { return ( [word, ...prevState] ) }) } } return ( <Text style={styles.paragraph}> {arr.map((el) => { let lc = el.toLowerCase() return ( <Text style={redHighlightedWords.includes(lc) ? styles.redHighlighted : yellowHighlightedWords.includes(lc) ? styles.yellowHighlighted : styles.paragraph} onPress={() => handlePress(el)} > {el + " "} </Text> ) })} </Text> ) } const styles = StyleSheet.create({ paragraph: { fontSize: 18, fontWeight: 'bold', textAlign: 'center', }, yellowHighlighted: { fontSize: 18, fontWeight: 'bold', textAlign: 'center', backgroundColor: "yellow", }, redHighlighted: { fontSize: 18, fontWeight: 'bold', textAlign: 'center', backgroundColor: "red", } });
App组件
import * as React from 'react'; import { Text, View, StyleSheet } from 'react-native'; import Constants from 'expo-constants'; import RenderedText from './components/RenderedText' export default function App() { return ( <View style={styles.container}> <Text> <RenderedText /> </Text> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', paddingTop: Constants.statusBarHeight, backgroundColor: '#ecf0f1', padding: 8, }, });
解决方案
你的思路完全可行,通过React.memo封装单个单词组件,配合状态存储优化,能直接解决全量重渲染的卡顿问题,具体实现如下:
1. 核心优化点
- 用React.memo缓存单词组件:只有当组件的props(单词内容、高亮状态、点击事件)变化时,才会重新渲染该组件
- 改用Set存储高亮单词:
Set.has()的查询效率远高于数组includes(),适合高频状态判断场景 - 稳定回调与缓存计算结果:用
useCallback缓存点击函数,useMemo缓存分割后的单词数组,避免父组件重渲染时触发子组件无意义更新
修改后的完整代码
RenderedText组件
import React, { useState, useCallback, useMemo } from 'react'; import { Text, View, StyleSheet} from 'react-native'; // 封装单个单词组件,React.memo确保只有props变化时才重渲染 const WordText = React.memo(({ word, isRed, isYellow, onPress }) => { return ( <Text style={isRed ? styles.redHighlighted : isYellow ? styles.yellowHighlighted : styles.paragraph} onPress={onPress} > {word + " "} </Text> ); }); export default function RenderedText() { // 用Set存储高亮单词,提升查询性能 const [yellowHighlightedWords, setYellowHighlightedWords] = useState(new Set(["west", "where", "neighborhood", "trouble", "cool"])); const [redHighlightedWords, setRedHighlightedWords] = useState(new Set(["playground", "school", "most"])); const str = "In West Philadelphia born and raised, On the playground is where I spent most of my days Chillin' out, maxin', relaxin' all cool And all shootin' some b-ball outside of the school When a couple of guys who were up to no good Started makin' trouble in my neighborhood I got in one little fight and my mom got scared"; // useMemo缓存分割后的单词数组,避免每次渲染都重新split const words = useMemo(() => str.split(/\s/g), [str]); // useCallback缓存点击事件,确保函数引用稳定 const handlePress = useCallback((word) => { const lowerWord = word.toLowerCase(); if (yellowHighlightedWords.has(lowerWord)) { setYellowHighlightedWords(prev => { const newSet = new Set(prev); newSet.delete(lowerWord); return newSet; }); } else if (redHighlightedWords.has(lowerWord)) { setRedHighlightedWords(prev => { const newSet = new Set(prev); newSet.delete(lowerWord); return newSet; }); } else { setYellowHighlightedWords(prev => new Set([...prev, lowerWord])); } }, [yellowHighlightedWords, redHighlightedWords]); return ( <Text style={styles.paragraph}> {words.map((word, index) => { const lowerWord = word.toLowerCase(); const isRed = redHighlightedWords.has(lowerWord); const isYellow = yellowHighlightedWords.has(lowerWord); // 添加唯一key,修复React列表渲染警告 return ( <WordText key={`${word}-${index}`} word={word} isRed={isRed} isYellow={isYellow} onPress={() => handlePress(word)} /> ); })} </Text> ); } const styles = StyleSheet.create({ paragraph: { fontSize: 18, fontWeight: 'bold', textAlign: 'center', }, yellowHighlighted: { fontSize: 18, fontWeight: 'bold', textAlign: 'center', backgroundColor: "yellow", }, redHighlighted: { fontSize: 18, fontWeight: 'bold', textAlign: 'center', backgroundColor: "red", } });
App组件
无需修改,保持原有代码即可。
优化效果说明
- 点击单词时,只有该单词的所有实例会重新渲染,其他单词组件完全不会更新,彻底解决全量重渲染导致的卡顿
- Set的使用大幅提升了状态判断效率,单词数量越多效果越明显
- 稳定的回调和缓存数组避免了子组件的无意义重渲染,进一步降低性能消耗
内容的提问来源于stack exchange,提问作者DingleberrySmith
相关产品推荐
相关产品推荐

