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

React Native:用useRef修改动态列表选中按钮颜色的问题排查

React Native 列表项选中状态样式修复方案

问题根源

  1. 单个useRef失效:循环渲染子组件时,所有组件共享同一个useRef,每次迭代都会覆盖current值,最终仅指向最后一个子组件。
  2. 数组ref+全选bug:
    • invoiceTitleRef是普通数组,组件重渲染时会被重置,无法稳定保存子组件引用。
    • 把isSelected设为字符串"true"/"false",但JS中字符串"false"会被判定为真值,导致所有按钮都显示选中状态。
    • 冗余使用useImperativeHandle,完全可以通过props传递状态,不需要ref获取子组件数据。

最优解决方案

核心逻辑:父组件统一管理选中状态,子组件根据父传的状态渲染样式,彻底抛弃不必要的ref

修正后的父组件

import { useState, View, StyleSheet } from 'react-native';
import InvoiceTitle from './InvoiceTitle';
import AppBackground from './AppBackground';

const Usage = () => {
  const [data, setData] = useState(UsageDataMock1);
  // 用状态记录当前选中的标题(用ID更可靠,避免标题重复)
  const [selectedTitle, setSelectedTitle] = useState('');

  const handleTitleSelect = (title) => {
    setSelectedTitle(title);
  };

  return (
    <AppBackground>
      <View style={styles.container}>
        {data.map((item) => (
          <InvoiceTitle
            key={item.id}
            title={item.title}
            isSelected={item.title === selectedTitle}
            onSelect={() => handleTitleSelect(item.title)}
          />
        ))}
      </View>
    </AppBackground>
  );
};

const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    marginTop: 50,
  },
});

export default Usage;

修正后的子组件

import { Pressable, StyleSheet } from 'react-native';
import AppText from './AppText';

// 无需forwardRef和useImperativeHandle,逻辑完全通过props实现
const InvoiceTitle = ({ title, isSelected, onSelect }) => {
  return (
    <Pressable
      onPress={onSelect}
      style={({ pressed }) => [
        styles.titleContainer,
        {
          backgroundColor: isSelected ? 'red' : 'white', // 选中红,未选白
          opacity: pressed ? 0.5 : 1,
        },
      ]}
    >
      <AppText>{title}</AppText>
    </Pressable>
  );
};

const styles = StyleSheet.create({
  titleContainer: {
    marginHorizontal: 10,
    alignSelf: 'flex-start',
    paddingHorizontal: 10,
    paddingVertical: 8,
    borderRadius: 12,
  },
});

export default InvoiceTitle;

interface InvoiceTitleProps {
  title: string;
  isSelected: boolean;
  onSelect: () => void;
}

关键优化点

  • 移除冗余ref:不需要通过ref获取子组件数据,点击事件直接传递选中值给父组件。
  • 状态统一管理:父组件用selectedTitle记录选中项,子组件通过isSelected属性判断自身状态,避免状态分散。
  • 修复类型错误:用布尔值直接判断选中状态,避免字符串转布尔的逻辑错误。
  • 简化组件逻辑:子组件仅负责渲染和触发点击,状态完全由父组件控制,符合React单向数据流原则。

内容的提问来源于stack exchange,提问作者Anil Saxena

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 19:40:31