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

React Native动态数据下点击按钮批量变色而非单个的问题

点击单个按钮导致所有按钮变色的问题修复

问题根源

你在父组件的onChange函数里,给isSelected赋值的是字符串类型的'true'和'false',但子组件中selected属性期望的是布尔类型的值。在JavaScript里,任何非空字符串都会被判定为true,所以不管数据里的isSelected是'true'还是'false',子组件的条件判断selected ? 'red' : 'blue'都会走true分支,所有按钮都显示红色。

另外代码还有两个可优化的点:

  • 没必要通过ref获取选中的title,子组件点击时已经把title作为参数传给了onChange,直接用这个参数就行
  • 父组件中map回调的index参数和外层onChange的index重名,会导致变量覆盖,虽然当前不影响功能,但容易引发其他问题

修复后的代码

父组件修改

const Usage = () => {
    const [data, setData] = useState(UsageDataMock1);
    // 如果不需要ref可以直接删掉下面这行
    const invoiceTitleRef = [];

    const onChange = (_, selectedTitle) => {
        // 直接用子组件传过来的selectedTitle,不用ref
        setData(data.map(item => {
            // 赋值布尔类型的true/false,不是字符串
            return {
                ...item,
                isSelected: item.title === selectedTitle
            };
        }));
    };

    return (
        <AppBackground>
            <View style={{flexDirection: 'row', marginTop: 50}}>
                {data.map((item, index) => (
                    <InvoiceTitle 
                        key={item.id} 
                        title={item.title} 
                        selected={item?.isSelected ?? false} // 兜底默认布尔值
                        onChange={onChange} 
                        index={index} 
                    />
                ))}
            </View>
        </AppBackground>
    );
};

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

export default Usage;

子组件修改(移除无用ref,简化逻辑)

const InvoiceTitle = ({
    title,
    onChange,
    index,
    selected = false,
    ...props
}: InvoiceTitleProps) => {
    // 不需要ref的话直接删掉下面这部分,如果确实需要ref再保留
    // useImperativeHandle(ref, () => ({
    //    getSelectedTitle : () => title
    // }))

    const onClick = () => {
        onChange(index, title);
    };

    return (
        <Pressable 
            onPress={onClick} 
            style={({pressed}) => [
                styles.titleContainer,
                {
                    backgroundColor: selected ? 'red' : 'blue', 
                    opacity: pressed ? 0.5 : 1
                }
            ]}>
            <AppText>{title}</AppText>
        </Pressable>
    );
};

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

export default InvoiceTitle;

interface InvoiceTitleProps {
    title : string;
    onChange : (index: number, title: string) => void;
    index : number;
    selected? : boolean; // 设为可选,配合默认值
}

关键修复点总结

  • 把isSelected的赋值从字符串'true'/'false'改成布尔值true/false
  • 移除不必要的ref引用,直接用子组件传递的title参数
  • 给selected属性设置兜底的布尔默认值,避免初始状态下undefined引发的判断问题

内容的提问来源于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.11 02:40:25