简体   繁体   English

单击FlatList元素时如何打开带有项目信息的Modal?

[英]How to open Modal with item information when clicking a FlatList element?

What I am trying to achieve is to open a modal dialog when the user press on one of the items of a FlatList component. 我要实现的目标是,当用户按下FlatList组件之一时,打开一个模式对话框。 The code of this list looks like this: 此列表的代码如下所示:

class MyItem extends React.Component { 
  _onPress = () => { 
    this.props.onPressItem(this.props.item); 
  }; 
  render() { 
    return(
        <TouchableOpacity 
            {...this.props}
            onPress={this._onPress}
            >
            <Text style={styles.itemText}> {this.props.item.name}</Text>
        </TouchableOpacity>
    ) 
  } 
}

export default class MyList extends React.PureComponent {
    constructor(props) {
        super(props);
        this.state = {
            data: {}, // some data correctly loaded
            isModalVisible: false
        };
    };

    _onPressItem = (item) => { 
        this._showModal;
    };

    _showModal = () => this.setState({ isModalVisible: true })

    _keyExtractor = (item, index) => item.id;

    _renderItem = ({item}) => (
        <MyItem 
            style={styles.row}
            item={item}
            onPressItem={this._onPressItem}
        />
    );

    render() {
      return(
        <KeyboardAvoidingView behavior="padding" style={styles.container}>
          <View style={styles.titleContainer}>
              <Text style={styles.title}>Tittle</Text>
          </View>
          <ScrollView style={styles.container}>
              <FlatList 
                  data={this.state.data}
                  ItemSeparatorComponent = {this._flatListItemSeparator}
                  renderItem={this._renderItem}
                  keyExtractor={this._keyExtractor}
              />
          </ScrollView>
          <MyModal modalVisible={this.state.isModalVisible}/>
        </KeyboardAvoidingView>
      );
    }
}

Styles, FlatList data and some functions have been removed because they are not relevant for this issue. 样式,FlatList数据和某些功能已删除,因为它们与此问题无关。

As you can see, MyModal component is declared after ScrollView component. 如您所见, MyModal组件在ScrollView组件之后声明。 The code is based on the use of react-native Modal component: 该代码基于使用react-native Modal组件:

export default class MyModal extends Component {
  constructor(props) {
    super(props);
    this.state = {
        isModalVisible: props.modalVisible
    };
  };

  _setModalVisible(visible) {
    this.setState({modalVisible: visible});
  }

  render() {
    return (
        <View>
            <Modal
            animationType="slide"
            transparent={false}
            visible={this.state.modalVisible}
            onRequestClose={() => {alert("Modal has been closed.")}}
            >
                <View style={styles.container}>
                    <View style={styles.innerContainer}>
                        <Text>Item Detail</Text>
                        <TouchableHighlight
                            style={styles.buttonContainer}
                            onPress={() => { this._setModalVisible(false) }}>
                            <Text style={styles.buttonText}>Close</Text> 
                        </TouchableHighlight>
                    </View>
                </View>
            </Modal>
        </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    padding: 20,
    backgroundColor: 'transparent',
  },
  innerContainer: {
    borderRadius: 10,
    alignItems: 'center',
    backgroundColor: '#34495e',
 },
 buttonContainer: {
    paddingVertical: 15,
    marginTop: 20,
    backgroundColor: '#2c3e50',
    borderRadius: 15
 },
 buttonText: {
    textAlign: 'center',
    color: '#ecf0f1',
    fontWeight: '700'
 },
});

Current behaviour is MyModal component being displayed when I access to MyList component for the first time, I can close it and then the FlatList is there but when a list item is pressed, MyModal component is not displayed. 目前的行为是MyModal当我访问显示组件MyList组件的第一次,我可以关闭它,然后FlatList是存在的,但是当按下列表项, MyModal不显示组件。

How can I manage to hide Modal and open it only when a list item is pressed? 仅在按下列表项时,如何才能隐藏Modal并打开它?

Another doubt related to this is: 与此相关的另一个疑问是:

How to pass the pressed item object to MyModal component? 如何将按下的项目对象传递给MyModal组件?

Thanks in advance! 提前致谢!

class MyItem extends React.Component { 
  _onPress = () => { 
    this.props.onPressItem(this.props.item); 
  }; 
  render() { 
    return(
        <TouchableOpacity 
            {...this.props}
            onPress={this._onPress}
            >
            <Text style={styles.itemText}> {this.props.item.name}</Text>
        </TouchableOpacity>
    ) 
  } 
}

export default class MyList extends React.PureComponent {
    constructor(props) {
        super(props);
        this.state = {
            data: {}, // some data correctly loaded
            isModalVisible: false,
            selectedItem: null
        };
    };

    _onPressItem = (item) => { 
        this._showModal(item);
    };

    _hideMyModal = () => {
        this.setState({isModalVisible: false})
    }

    _showModal = (item) => this.setState({ isModalVisible: true, 
    selectedItem: item })

    _keyExtractor = (item, index) => item.id;

    _renderItem = ({item}) => (
        <MyItem 
            style={styles.row}
            item={item}
            onPressItem={() => this._onPressItem(item)}
        />
    );

    render() {
      return(
        <KeyboardAvoidingView behavior="padding" style={styles.container}>
          <View style={styles.titleContainer}>
              <Text style={styles.title}>Tittle</Text>
          </View>
          <ScrollView style={styles.container}>
              <FlatList 
                  data={this.state.data}
                  ItemSeparatorComponent = {this._flatListItemSeparator}
                  renderItem={this._renderItem}
                  keyExtractor={this._keyExtractor}
              />
          </ScrollView>
          { this.state.isModalVisible && <MyModal selectedItem={this.state.selectedItem} modalVisible={this.state.isModalVisible} hideModal={this_hideMyModal} /> }
        </KeyboardAvoidingView>
      );
    }
}

When you press the item in FlatList, just set it in the state and pass it as a prop to MyModal component(pretty self explanatory). 当您在FlatList中按下该项目时,只需将其设置为状态,然后将其作为道具传递给MyModal组件即可。

export default class MyModal extends Component {
  constructor(props) {
    super(props);
    this.state = {
        isModalVisible: props.modalVisible
    };
  };

  _setModalVisible(visible) {
    this.setState({modalVisible: visible});
  }

  render() {
    return (
        <View>
            <Modal
            animationType="slide"
            transparent={false}
            visible={this.state.isModalVisible}
            onRequestClose={() => {alert("Modal has been closed.")}}
            >
                <View style={styles.container}>
                    <View style={styles.innerContainer}>
                        <Text>Item Detail</Text>
                        <TouchableHighlight
                            style={styles.buttonContainer}
                            onPress={() => { this.props.hideModal() }}>
                            <Text style={styles.buttonText}>Close</Text> 
                        </TouchableHighlight>
                    </View>
                </View>
            </Modal>
        </View>
    );
  }
}

In your previous code in MyModal you were doing this --> onPress={() => { this._setModalVisible(false) }}> which will hide the modal in the MyModal class but MyModal is still rendered in the MyList class. 在以前的代码MyModal你这样做- > onPress={() => { this._setModalVisible(false) }}>这将隐藏在该模式MyModal类,但MyModal仍然在呈现MyList类。 So you might be unable to click the FlatList item again. 因此,您可能无法再次单击FlatList项目。 I passed a prop hideModal which will remove the MyModal component from the MyList . 我通过一个道具hideModal这将删除MyModal从组件MyList In my revised code you don't need to pass modalVisible prop also, but its up to you for that. 在我的修订代码中,您也不需要通过modalVisible ,但是这取决于您。

Passing the item through to the modal item传递给模态

To pass the selected item to your modal, you'll need to add it as a prop on your Modal component. 要将所选项目传递给模态,您需要将其作为prop添加到Modal组件上。

You can remember the selected item in MyList 's state: 您可以记住处于MyList状态的所选项目:

_onPressItem = (item) => { 
    this._showModal(item);
};

_showModal = (selectedItem) => this.setState({ isModalVisible: true, selectedItem })

And then pass it through to the modal when you render it from MyList : 然后从MyList render它时, render其传递给模态:

// ...
      </ScrollView>
      <MyModal 
        modalVisible={this.state.isModalVisible} 
        selectedItem={this.state.selectedItem} />
    </KeyboardAvoidingView>
// ...

Controlling the modal's visibility 控制模式的可见性

Currently you have a modal visibility boolean in both MyList 's state ( isModalVisible , which is passed through to MyModal as the modalVisible prop) and also in MyModal 's state ( modalVisible ). 目前,你有两种模态的知名度布尔MyList的状态( isModalVisible ,这是通过传递给MyModal作为modalVisible道具)以及在MyModal的状态( modalVisible )。 There's no need for the last one - it'll just give you a headache trying to keep them in sync. 不需要最后一个-它只会让您头疼,无法保持同步。 Just use the props to " control " MyModal , keeping a single source of truth, and pass a callback to allow MyModal to tell MyList that the modal should be dismissed. 只需使用道具“ 控制MyModal ,保持真相的单一来源,并通过回调允许MyModal告诉MyList该模式应予以驳回。

// ...
      </ScrollView>
      <MyModal 
        modalVisible={this.state.isModalVisible} 
        selectedItem={this.state.selectedItem}
        onDismiss={this._hideModal} />
    </KeyboardAvoidingView>
// ...

A new stateless MyModal : 一个新的无状态MyModal

export default class MyModal extends Component {    
  render() {
    return (
        <View>
            <Modal
            animationType="slide"
            transparent={false}
            visible={this.props.modalVisible}
            onRequestClose={() => { this.props.onDismiss() }}
            >
                <View style={styles.container}>
                    <View style={styles.innerContainer}>
                        <Text>Item Detail</Text>
                        <TouchableHighlight
                            style={styles.buttonContainer}
                            onPress={() => { this.props.onDismiss() }}>
                            <Text style={styles.buttonText}>Close</Text> 
                        </TouchableHighlight>
                    </View>
                </View>
            </Modal>
        </View>
    );
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM