You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于指定参数仅重渲染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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 01:01:11