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

React Native渲染200+可点击视图的性能优化方案咨询

React Native Expo游戏中大量点击视图的响应延迟优化

问题描述

在Expo环境下开发React Native游戏,需渲染200+带点击功能的视图。点击视图时需执行切换背景色、更新gameContext中分数的操作,但点击后响应存在延迟。以下是相关组件代码:

CheckBoxCom组件

import { useEffect, useState, memo } from "react";
import { useContext } from "react";
import { gameContext } from "./gameContext";
import { Pressable, View } from "react-native";
function CheckBoxCom() {
  const [active, setActive] = useState(false);
  const { score, setScore } = useContext(gameContext);
  useEffect(() => {
    let time = setTimeout(() => {
      setActive(false);
    }, Math.floor(Math.random() * 35000));

    return () => clearTimeout(time);
  }, [active]);
  const handlePress = () => {
    if (active) return;
    setActive(true);
    setScore(score + 1);
  };

  return (
    <View>
      <Pressable onPress={handlePress}>
        <View
          style={{
            width: 20,
            height: 20,
            borderWidth: 2,
            borderColor: active ? "green" : "gray",
            margin: 3,
            borderRadius: 3,
            backgroundColor: active ? "green" : null,
          }}
        ></View>
      </Pressable>
    </View>
  );
}

export default memo(CheckBoxCom);

Game页面组件

import { useContext, useEffect, useState } from "react";
import { StatusBar } from "expo-status-bar";
import { StyleSheet, Text, View, FlatList } from "react-native";
import CheckBox from "./CheckBox";
import { gameContext } from "./gameContext";

export default function Game({ navigation }) {
  const { score, time, setTime, boxList } = useContext(gameContext);
  const [intervalId, setIntervalId] = useState("");

  useEffect(() => {
    const int = setInterval(() => {
      setTime((prvTime) => prvTime - 1);
    }, 1000);
    setIntervalId(int);
    return () => clearInterval(int);
  }, []);

  if (time === 0) {
    clearInterval(intervalId);
    navigation.navigate("Score", { score });
  }

  return (
    <View style={{ flex: 1 }}>
      <StatusBar style="auto" />
      <View style={styles.textHeader}>
        <Text>Score : {score}</Text>
        <Text>Time Left: {time}s</Text>
      </View>
      <View style={styles.checkBoxContainer}>
        <FlatList
          style={{ alignSelf: "center" }}
          data={boxList}
          initialNumToRender={50}
          numColumns={12}
          renderItem={(i) => <CheckBox />}
          keyExtractor={(i) => i.toString()}
          scrollEnabled={false}
        />
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  textHeader: {
    display: "flex",
    flexDirection: "row",
    justifyContent: "space-between",
    width: "100%",
    marginTop: 40,
    paddingHorizontal: 30,
  },
  checkBoxContainer: {
    margin: 20,
    display: "flex",
    flexWrap: "wrap",
    height: "80%",
    overflow: "hidden",
    flexDirection: "row",
  },
});

优化方案及代码修改

1. 修复setScore的闭包陷阱

原代码中setScore(score + 1)依赖闭包捕获的旧score值,可能导致分数更新不及时,改为函数式更新确保获取最新状态:

// CheckBoxCom组件中handlePress修改为
const handlePress = () => {
  if (active) return;
  setActive(true);
  setScore(prevScore => prevScore + 1);
};

2. 简化组件层级,减少不必要嵌套

移除CheckBoxCom中外层多余的View,直接用Pressable包裹内部视图,减少组件层级提升渲染效率:

// CheckBoxCom组件的return部分修改为
return (
  <Pressable onPress={handlePress} style={{ margin: 3 }}>
    <View
      style={{
        width: 20,
        height: 20,
        borderWidth: 2,
        borderColor: active ? "green" : "gray",
        borderRadius: 3,
        backgroundColor: active ? "green" : null,
      }}
    />
  </Pressable>
);

3. 优化定时器逻辑,减少不必要的定时器创建

调整useEffect的触发条件,仅当active变为true时才启动定时器,避免无效操作:

// CheckBoxCom组件中的useEffect修改为
useEffect(() => {
  if (!active) return;
  const timer = setTimeout(() => {
    setActive(false);
  }, Math.floor(Math.random() * 35000));
  return () => clearTimeout(timer);
}, [active]);

4. 将游戏结束逻辑移至useEffect,避免渲染阶段副作用

原Game组件中在渲染阶段直接处理time === 0的逻辑,会导致重复执行和性能损耗,改为监听time变化的useEffect:

// Game组件中添加useEffect监听time变化
useEffect(() => {
  if (time === 0) {
    clearInterval(intervalId);
    navigation.navigate("Score", { score });
  }
}, [time, intervalId, navigation, score]);

// 移除原渲染阶段的if判断
// if (time === 0) { ... }

5. 优化FlatList配置,提升批量渲染性能

调整FlatList的渲染参数,让组件分批渲染避免主线程阻塞:

// Game组件中的FlatList属性修改为
<FlatList
  style={{ alignSelf: "center" }}
  data={boxList}
  initialNumToRender={100} // 初始渲染数量,根据屏幕适配调整
  maxToRenderPerBatch={20} // 每批渲染的组件数
  windowSize={5} // 控制预渲染的范围,减少内存占用
  removeClippedSubviews={true} // 自动裁剪离屏组件
  numColumns={12}
  renderItem={() => <CheckBox />}
  keyExtractor={(item) => item.toString()}
  scrollEnabled={false}
/>

6. 清理冗余样式

移除Game组件样式中无效的display: "flex"(React Native中默认flex布局):

const styles = StyleSheet.create({
  textHeader: {
    flexDirection: "row",
    justifyContent: "space-between",
    width: "100%",
    marginTop: 40,
    paddingHorizontal: 30,
  },
  checkBoxContainer: {
    margin: 20,
    height: "80%",
    overflow: "hidden",
  },
});

修改后的完整代码

CheckBoxCom组件

import { useEffect, useState, memo } from "react";
import { useContext } from "react";
import { gameContext } from "./gameContext";
import { Pressable, View } from "react-native";

function CheckBoxCom() {
  const [active, setActive] = useState(false);
  const { setScore } = useContext(gameContext);

  useEffect(() => {
    if (!active) return;
    const timer = setTimeout(() => {
      setActive(false);
    }, Math.floor(Math.random() * 35000));
    return () => clearTimeout(timer);
  }, [active]);

  const handlePress = () => {
    if (active) return;
    setActive(true);
    setScore(prevScore => prevScore + 1);
  };

  return (
    <Pressable onPress={handlePress} style={{ margin: 3 }}>
      <View
        style={{
          width: 20,
          height: 20,
          borderWidth: 2,
          borderColor: active ? "green" : "gray",
          borderRadius: 3,
          backgroundColor: active ? "green" : null,
        }}
      />
    </Pressable>
  );
}

export default memo(CheckBoxCom);

Game页面组件

import { useContext, useEffect, useState } from "react";
import { StatusBar } from "expo-status-bar";
import { StyleSheet, Text, View, FlatList } from "react-native";
import CheckBox from "./CheckBox";
import { gameContext } from "./gameContext";

export default function Game({ navigation }) {
  const { score, time, setTime, boxList } = useContext(gameContext);
  const [intervalId, setIntervalId] = useState(null);

  useEffect(() => {
    const int = setInterval(() => {
      setTime(prvTime => prvTime - 1);
    }, 1000);
    setIntervalId(int);
    return () => clearInterval(int);
  }, []);

  useEffect(() => {
    if (time === 0) {
      clearInterval(intervalId);
      navigation.navigate("Score", { score });
    }
  }, [time, intervalId, navigation, score]);

  return (
    <View style={{ flex: 1 }}>
      <StatusBar style="auto" />
      <View style={styles.textHeader}>
        <Text>Score : {score}</Text>
        <Text>Time Left: {time}s</Text>
      </View>
      <View style={styles.checkBoxContainer}>
        <FlatList
          style={{ alignSelf: "center" }}
          data={boxList}
          initialNumToRender={100}
          maxToRenderPerBatch={20}
          windowSize={5}
          removeClippedSubviews={true}
          numColumns={12}
          renderItem={() => <CheckBox />}
          keyExtractor={(item) => item.toString()}
          scrollEnabled={false}
        />
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  textHeader: {
    flexDirection: "row",
    justifyContent: "space-between",
    width: "100%",
    marginTop: 40,
    paddingHorizontal: 30,
  },
  checkBoxContainer: {
    margin: 20,
    height: "80%",
    overflow: "hidden",
  },
});

内容的提问来源于stack exchange,提问作者Khorshed Alam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 11:27:28