React Native: FlatList открывает модальный режим для всех элементов вместо выбранного элемента

#javascript #react-native #react-native-flatlist #react-native-modal

#javascript #react-native #react-native-flatlist #react-native-modal

Вопрос:

Я использую React Native FlatList и React Native Modal.

При нажатии на элемент из FlatList я хочу просмотреть только 1 модальный (содержащий сведения о выбранном элементе).

Однако, если в FlatList есть 4 элемента, выбор 1 элемента приводит к появлению всех 4 модалов.

Могу ли я в любом случае отобразить только 1 модальный для 1 выбранного элемента в FlatList вместо нескольких модальных?

Фрагмент кода ниже (некоторые строки кода были удалены за ненадобностью):

     constructor(props) {
            super(props);
            this.state = {
                dataSource: [],
                isLoading: true,
                modalVisible: false,
            }
        }
    
    setModalVisible = (visible) => {
            this.setState({ modalVisible: visible });
        } 
        
    
        viewModal(item, price) {
            const { modalVisible } = this.state;
            return (
                <Modal
                    statusBarTranslucent={true}
                    animationType={"slide"}
                    transparent={true}
                    visible={modalVisible}
                    onRequestClose={() => {
                        Alert.alert("Modal has been closed.");
                    }}
                >
                    <View>
                        <View>
                            <View>
                                <Text>
                                    Appointment Start Time:
                                </Text>
                                <Text>
                                    {moment(item.time_start).format('h:mm a')}
                                </Text>
                            </View>
    
                            <View>
                                <Text>
                                    Appointment End Time:
                                </Text>
                                <Text>
                                    {moment(item.end_start).format('h:mm a')}
                                </Text>
                            </View>
    
                            
    
                            
                            <View style={styles.row}>
                                <Text>
                                    Total:
                                </Text>
                                <Text>
                                    {price}
                                </Text>
                            </View>
                            
                            <View>
                                <View>
                                    <Button
                                        mode="outlined"
                                        onPress={() => {
                                            this.setModalVisible(!modalVisible);
                                        }}
                                    >
                                        {'Cancel'}
                                    </Button>
                                </View>
                                
                                <View>
                                    <Button
                                        mode="contained"
                                        onPress={() => {
                                            this.setModalVisible(!modalVisible);
                                        }}
                                    >
                                        {'Accept'}
                                    </Button>
                                </View>
                            </View>
                        </View>
                    </View>
                </Modal>
            );
        }
    
        viewFreelancerTime() {
            return (
                <View>
                    <FlatList
                        renderItem={({ item }) => {
                            let totalPrice = (parseFloat(item.service_price)   parseFloat(item.service_deposit)).toFixed(2);
                            return (
                                <Container>
                                    {this.viewModal(item, totalPrice)}
                                    <TouchableNativeFeedback
                                        onPress={() => {
                                            this.setModalVisible(true);
                                        }}
                                    >
                                        <View>
                                            <View>
                                                <Text>
                                                    {moment(item.time_start).format('h:mm a')}
                                                </Text>
                                            </View>
    
                                            <View>
                                                <Text>
                                                    {totalPrice}
                                                </Text>
                                            </View>
                                        </View>
                                    </TouchableNativeFeedback>
                                </Container>
                            );
                        }}
                    />
                </View>
            );
        }

render() {
            return (
                <>
                    <View style={{ flex: 1 }}>
                        {this.viewFreelancerTime()}
                    </View>

                </>
            );
    };
  

Ответ №1:

Проблема в том, что вы визуализируете модал в методе renderItem, поэтому каждый раз, когда вы выбираете элемент, модал будет открываться в каждом визуализированном элементе.

Чтобы решить эту проблему, вам нужно будет отобразить пользовательский модальный компонент с абсолютной позицией на том же уровне вашего FlatList и передать информацию о выбранном элементе в качестве реквизита.

Обновить

Просто что-то вроде этого:

 import React, {useState} from "react";
import { Modal } from "react-native";

export default function MyFlatList(props) {
  const [selectedItem, setSelectedItem] = useState(null);

  const handleOnSelectItem = (item) => {
    setSelectedItem(item);
  };

  const handleOnCloseModal = () => {
    setSelectedItem(null);
  };

  renderItem = ({ item }) => {
    return (
      <Container>
        <TouchableNativeFeedback onPress={() => handleOnSelectItem(item)}>
          <View>
            <View>
              <Text>{moment(item.time_start).format("h:mm a")}</Text>
            </View>

            <View>
              <Text>{totalPrice}</Text>
            </View>
          </View>
        </TouchableNativeFeedback>
      </Container>
    );
  };

  return (
    <View>
      <FlatList renderItem={this.renderItem} />
      <CustomModal isVisible={selectedItem} selectedItem={selectedItem} onClose={handleOnCloseModal} />
    </View>
  );
}

export function CustomModal(props) {
  const { isVisible, item, onClose,  /*...*/ } = props;

  // Play with the item data
  let totalPrice = (
    parseFloat(item.servicePrice)   parseFloat(item.serviceDeposit)
  ).toFixed(2);

  return <Modal visible={isVisible} onRequestClose={onClose}>{/*...*/}</Modal>; // Render things inside the data
}
  

Я предлагаю вам выполнить разбивку на страницы и поиграть с собственными реквизитами FlatList, если вы собираетесь реализовать бесконечную прокрутку.

Pd: чтобы уменьшить повторную визуализацию из-за обновлений состояния, я повторно использую состояние SelectedItem, поэтому, если оно не равно null, модальное значение будет видно

Комментарии:

1. Monlina Спасибо за предложение. У вас случайно нет каких-либо примеров? Я довольно новичок в модальном и React Native в целом.

2. Я обновил ответ. Я не пробовал код, и я сделал это быстро, но что-то похожее.