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

React Native FlatList列表项RadioButton跨项选中方案

React Native FlatList 全局单选按钮实现问题修复

问题现象

使用FlatList渲染带升/降序单选按钮的列表时,仅第一个列表项的单选按钮可正常切换选中状态,其余列表项点击单选按钮无响应,交互要求为任意时刻全局仅可选中一个单选按钮。

问题根因

单选按钮触发状态更新时,仅更新了选中值(asc/desc),未同步记录选中按钮所属列表项的索引值,导致非首项的选中状态判断逻辑无法命中。

原问题代码

import {View, Text, Modal, StyleSheet, Button, FlatList,} from "react-native";
import { RadioButton } from "react-native-paper";

export default class Sortby extends React.Component {
  constructor(props) {
    super(props);
  }

  state = { 
    selectedIndex: 0,
    radioButtonValue: 'asc',     
  };

  onPress = (index) => {
    this.setState({ 
      selectedIndex: index,       
    });
  }

  onRadiochange = value => {
    this.setState({ 
      radioButtonValue: value,       
    });
  };

  datalist = () => {
    const gridFieldArray = [
      {"text":"Organization","key":"0.6722908010549572"},
      {"text":"Document No","key":"0.13707867638770266"},
      {"text":"Warehouse","key":"0.5240454674464342"},
      {"text":"Business Partner","key":"0.09679684535706568"},
      {"text":"Partner Address","key":"0.5778522746749319"},
      {"text":"Movement Date","key":"0.40039870656646404"}
      ]
    return gridFieldArray;
  };

  render() {
    return (
      <Modal visible={this.props.visible} transparent={true}>
        <View style={styles.modalStyles}>        

          <View style={styles.fieldsContainer}>
            <FlatList
              data={this.datalist()}
              extraData={this.state}
              renderItem={(itemData) => {
                const index = itemData.index;   
                
                return (
                  <View style={styles.fieldItem}>
                    <Text style={styles.fieldText}>{itemData.item.text}</Text>
                    <View style={styles.radioButtonContainer}>
                    <RadioButton.Group onValueChange={this.onRadiochange}>
                      <View style={styles.singleRadioButtonContainer}>
                        <Text>Asc</Text>
                        <RadioButton
                          color='#5d86d7'                        
                          value="asc"                      
                          status={ this.state.selectedIndex === index && this.state.radioButtonValue === 'asc' ? 'checked' : 'unchecked'}
                          onPress={() => {this.onPress(index)}}
                        />
                      </View>
                      <View style={styles.singleRadioButtonContainer}>
                        <Text>Desc</Text>
                        <RadioButton
                          color='#5d86d7'                        
                          value="desc"                      
                          status={ this.state.selectedIndex === index && this.state.radioButtonValue === 'desc' ?  'checked' : 'unchecked'}
                          onPress={() => {this.onPress(index)}}
                        />
                      </View>
                      </RadioButton.Group>
                    </View>
                  </View>
                );
              }}
              alwaysBounceVertical={false}
            />
          </View>
          <View style={styles.buttonContainer}>
            <View style={styles.button}>
              <Button title="OK" color="#5d86d7"></Button>
            </View>
            <View style={styles.button}>
              <Button
                title="Cancel"
                color="#5d86d7"
                onPress={this.props.onCancel}
              ></Button>
            </View>
          </View>
        </View>
      </Modal>
    );
  }
}

const styles = StyleSheet.create({
  modalStyles: {
    height: "auto",
    width: "90%",
    flexDirection: "column",
    justifyContent: "flex-start",
    alignItems: "center",
    backgroundColor: "#fff",
    borderColor: "#777",
    borderWidth: 1,
    paddingTop: 15,
    marginLeft: 20,
    marginTop: 50,
  },
  fieldsContainer: {
    width: "100%",
  },
  fieldItem: {
    flexDirection: "row",
    alignItems: "center",
    justifyContent: "space-between",
    paddingLeft: 12,
    borderBottomWidth: 1,        
    borderBottomColor: "#ebebeb",
  },
  fieldText: {
    color: "#444",
  },
  radioButtonContainer: {
    flexDirection: "row",
    justifyContent: "flex-start",
    alignItems: "center",
  },
  singleRadioButtonContainer: {
    flexDirection: "row",
    justifyContent: "flex-start",
    alignItems: "center",
    marginRight: 10,
  }, 
  buttonContainer: {
    flexDirection: "row",
    justifyContent: "center",
    alignItems: "center",
    marginTop: 20,
    marginBottom: 20,
  },
  button: {
    width: "20%",
    marginHorizontal: 8,
  },
});

核心修改点

  • 调整onRadiochange方法入参,同时接收当前列表项索引index和选中值value,状态更新时同步修改selectedIndex和radioButtonValue两个字段,避免索引和选中值不同步
  • 渲染列表项时,将当前项的index透传给RadioButton.Group的onValueChange回调,替代原有仅传递选中值的绑定逻辑,保证点击任意项的单选按钮时,都能正确关联所属列表项

修复后可运行代码

import {View, Text, Modal, StyleSheet, Button, FlatList,} from "react-native";
import { RadioButton } from "react-native-paper";

export default class Sortby extends React.Component {
  constructor(props) {
    super(props);
  }

  state = { 
    selectedIndex: 0,
    radioButtonValue: 'asc',     
  };

  onPress = (index) => {
    this.setState({ 
      selectedIndex: index,       
    });
  }

 onRadiochange = (index, value) => {
    this.setState({ 
      radioButtonValue: value,   
      selectedIndex: index   
    });
  };

  datalist = () => {
    const gridFieldArray = [
      {"text":"Organization","key":"0.6722908010549572"},
      {"text":"Document No","key":"0.13707867638770266"},
      {"text":"Warehouse","key":"0.5240454674464342"},
      {"text":"Business Partner","key":"0.09679684535706568"},
      {"text":"Partner Address","key":"0.5778522746749319"},
      {"text":"Movement Date","key":"0.40039870656646404"}
      ]
    return gridFieldArray;
  };

  render() {
    return (
      <Modal visible={this.props.visible} transparent={true}>
        <View style={styles.modalStyles}>        

          <View style={styles.fieldsContainer}>
            <FlatList
              data={this.datalist()}
              extraData={this.state}
              renderItem={(itemData) => {
                const index = itemData.index;   
                
                return (
                  <View style={styles.fieldItem}>
                    <Text style={styles.fieldText}>{itemData.item.text}</Text>
                    <View style={styles.radioButtonContainer}>
                    <RadioButton.Group onValueChange={value => this.onRadiochange(index, value)}>
                      <View style={styles.singleRadioButtonContainer}>
                        <Text>Asc</Text>
                        <RadioButton
                          color='#5d86d7'                        
                          value="asc"                      
                          status={ this.state.selectedIndex === index && this.state.radioButtonValue === 'asc' ? 'checked' : 'unchecked'}
                          onPress={() => {this.onPress(index)}}
                        />
                      </View>
                      <View style={styles.singleRadioButtonContainer}>
                        <Text>Desc</Text>
                        <RadioButton
                          color='#5d86d7'                        
                          value="desc"                      
                          status={ this.state.selectedIndex === index && this.state.radioButtonValue === 'desc' ?  'checked' : 'unchecked'}
                          onPress={() => {this.onPress(index)}}
                        />
                      </View>
                      </RadioButton.Group>
                    </View>
                  </View>
                );
              }}
              alwaysBounceVertical={false}
            />
          </View>
          <View style={styles.buttonContainer}>
            <View style={styles.button}>
              <Button title="OK" color="#5d86d7"></Button>
            </View>
            <View style={styles.button}>
              <Button
                title="Cancel"
                color="#5d86d7"
                onPress={this.props.onCancel}
              ></Button>
            </View>
          </View>
        </View>
      </Modal>
    );
  }
}

const styles = StyleSheet.create({
  modalStyles: {
    height: "auto",
    width: "90%",
    flexDirection: "column",
    justifyContent: "flex-start",
    alignItems: "center",
    backgroundColor: "#fff",
    borderColor: "#777",
    borderWidth: 1,
    paddingTop: 15,
    marginLeft: 20,
    marginTop: 50,
  },
  fieldsContainer: {
    width: "100%",
  },
  fieldItem: {
    flexDirection: "row",
    alignItems: "center",
    justifyContent: "space-between",
    paddingLeft: 12,
    borderBottomWidth: 1,        
    borderBottomColor: "#ebebeb",
  },
  fieldText: {
    color: "#444",
  },
  radioButtonContainer: {
    flexDirection: "row",
    justifyContent: "flex-start",
    alignItems: "center",
  },
  singleRadioButtonContainer: {
    flexDirection: "row",
    justifyContent: "flex-start",
    alignItems: "center",
    marginRight: 10,
  }, 
  buttonContainer: {
    flexDirection: "row",
    justifyContent: "center",
    alignItems: "center",
    marginTop: 20,
    marginBottom: 20,
  },
  button: {
    width: "20%",
    marginHorizontal: 8,
  },
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 01:27:16