Динамическое значение в нескольких React Native Modal - PullRequest
0 голосов
/ 01 июня 2019

У меня есть 6 выпадающих списков на экране сравнения транспортных средств.Выпадающие списки создаются с помощью React Modal.Все данные в выпадающих списках являются динамическими.

dropdowns

Когда на страницу загружаются данные, которые отображаются в первых двух модальных моделях, марки автомобилей выбираются и отображаются в модальных выпадающих меню.

Когда выбирается марка автомобиля, делается еще один вызов API для получения моделей, доступных в этой марке.Эти данные заполняются во втором раскрывающемся списке.

Поскольку имеется два раскрывающихся списка для выбора модели для двух разных брендов, при выборе одного бренда оба раскрывающихся списка моделей обновляются.

Как я могу изменить свой код так, чтобы я мог сделать эту работу и сделать ее масштабируемой в будущем, если мне нужно будет добавить больше автомобилей для сравнения?

Compare.js

import React, { Component } from 'react'
import {
    View,
    StyleSheet,
    ScrollView,
    SafeAreaView,
    ActivityIndicator,
} from 'react-native';


import PickerModal from '../components/PickerModal';
import * as Api from "../api/app";


export default class CompareVehicles extends Component {
    constructor (props) {
        super(props);
        this.state = {
            isLoading: true,
            vehicleCompany: [],
            vehicleModel: [],
            vehicleSubModel: [],
        };
    }

    componentDidMount() {
        this.setState({
            isLoading: true,
        });
        this.getVehicleBrand();
    }

    getVehicleBrand = () => {
        Api.getVehicleBrands()
            .then((responseJson) => {
                console.log(responseJson);
                if (responseJson.success === true){
                    this.setState({
                        isLoading: false,
                        vehicleCompany : responseJson.data
                    });
                }  else {
                    alert("Error Loading Content")
                }
            });
    };

    submitBrand = async (data) => {
        Api.getVehicleModel(data)
            .then((responseJson) => {
                console.log(responseJson);
                if (responseJson.success === true){
                    this.setState({
                        vehicleModel: responseJson.data
                    });
                }  else {
                    alert("Error Adding Content")
                }
            });
    };

    submitModel = (data) => {
        console.log(data)
    };

    submitVariant = (data) => {
        console.log(data)
    };

    _renderPickerModal = (index) => {
        if (this.state.vehicleSubModel.length) {
            return (
                <View>
                    <PickerModal onSubmit={this.submitBrand} type={'light-dropdown'} data={this.state.vehicleCompany}/>
                    <PickerModal onSubmit={this.submitModel} type={'light-dropdown'} data={this.state.vehicleModel}/>
                    <PickerModal onSubmit={this.submitVariant} type={'light-dropdown'} data={this.state.vehicleSubModel}/>
                </View>
            )
        } else if(this.state.vehicleModel.length) {
            return (
                <View>
                    <PickerModal onSubmit={this.submitBrand} type={'light-dropdown'} data={this.state.vehicleCompany}/>
                    <PickerModal onSubmit={this.submitModel} type={'light-dropdown'} data={this.state.vehicleModel}/>
                </View>
            )
        } else if (this.state.vehicleCompany.length) {
            return (
                <View>
                    <PickerModal onSubmit={this.submitBrand} type={'light-dropdown'} data={this.state.vehicleCompany}/>
                </View>
            )
        }
    };

    render() {
        if(this.state.isLoading) {
            return (
                <SafeAreaView style={[styles.safeArea, styles.alignJustifyCenter]}>
                    <ActivityIndicator/>
                </SafeAreaView>
            );
        } else {
            return (
                <SafeAreaView style={styles.safeArea}>
                    <ScrollView
                        style={styles.scrollView}
                        scrollEventThrottle={200}
                        directionalLockEnabled={true}>
                        <View style={{flexDirection: 'row'}}>
                            <View style={{flex: 1}}>
                                {this._renderPickerModal}
                            </View>
                            <View style={{flex: 1}}>
                                {this._renderPickerModal}
                            </View>
                        </View>
                    </ScrollView>
                </SafeAreaView>
            );
        }
    }
}


const styles = StyleSheet.create({
    safeArea: {
        flex: 1,
        backgroundColor: '#ffffff',
    },
    alignJustifyCenter: {
        alignItems: 'center',
        justifyContent: 'center'
    },
    scrollView: {
        flex: 1,
        backgroundColor: '#fff',
        paddingVertical: 15,
        paddingHorizontal: 20
    }
});

PickerModal.js

import React, {Component} from 'react';
import { StyleSheet, Text, View, Modal, TouchableHighlight, TouchableOpacity, TouchableWithoutFeedback } from 'react-native';
import PropTypes from 'prop-types';
import Ionicons from 'react-native-vector-icons/Ionicons';

export default class PickerModal extends Component {
    static propTypes = {
        type: PropTypes.string.isRequired,
        data: PropTypes.array.isRequired,
        onSubmit: PropTypes.func.isRequired,
        index: PropTypes.number
    };

    constructor(props) {
        super(props);

        this.state = {
            pickerTitle: this.props.data[0].name,
            pickerValue: this.props.data[0].id,
            pickerDisplayed: false,
            index: this.props.index
        }
    }

    componentDidMount = () => {
        console.log(this.props)
    };


    submit = () => {
        const { pickerValue } = this.state;
        const { index } = this.state;
        if (pickerValue) {
            this.props.onSubmit(pickerValue, index);
        }
    };

    setPickerValue(content, index) {
        this.setState({
            pickerTitle: content.name,
            pickerValue: content.id,
            index: index
        }, () => this.submit());

        this.togglePicker();
    }

    togglePicker() {
        this.setState({
            pickerDisplayed: !this.state.pickerDisplayed
        });
    }

    render() {
        return (
            <View style={styles.container}>
                <TouchableHighlight
                    style={{width: '90%'}}
                    onPress={() => this.togglePicker()}
                    underlayColor='transparent'>
                    <View style={[styles.dropdown, this.props.type == 'dark-dropdown' ? styles.darkDropdown : styles.lightDropdown]}>
                        <Text style={[this.props.type == 'dark-dropdown' ? styles.darkDropdown : {}, {flex: 1}]}>{this.state.pickerTitle}</Text>
                        <Ionicons name={'md-arrow-dropdown'} size={25} style={[this.props.type == 'dark-dropdown' ? styles.colorWhite : {}, {marginLeft: 5, marginTop: 5}]}/>
                    </View>
                </TouchableHighlight>
                <Modal visible={this.state.pickerDisplayed} animationType={"fade"} transparent={true}>
                    <TouchableOpacity
                        activeOpacity={1}
                        style={{flex:1, justifyContent:'center', alignItems:'center', backgroundColor: 'rgba(0, 0, 0, 0.3)'}}
                        onPressOut={() => {this.togglePicker()}}>
                        <TouchableWithoutFeedback>
                            <View style={{padding: 20,
                                backgroundColor: '#ffffff',
                                bottom: 0,
                                left: 0,
                                right: 0,
                                alignItems: 'center',
                                position: 'absolute', width: '100%' }}>
                                { this.props.data.map((value, index) => {
                                    return <TouchableHighlight key={index} onPress={() => this.setPickerValue(value, this.props.index)} style={{ paddingTop: 4, paddingBottom: 4 }}>
                                        <Text style={{fontSize: 15}}>{ value.name }</Text>
                                    </TouchableHighlight>
                                })}

                                <TouchableHighlight onPress={() => this.togglePicker()} style={{ paddingTop: 50, paddingBottom: 20 }}>
                                    <Text style={{color: '#999', fontSize: 20}}>Cancel</Text>
                                </TouchableHighlight>
                            </View>
                        </TouchableWithoutFeedback>
                    </TouchableOpacity>
                </Modal>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
    },
    colorWhite: {
        color: '#fff'
    },
    darkDropdown: {
        backgroundColor: '#000',
        borderRadius: 8,
        color: '#fff'
    },
    lightDropdown: {
        borderBottomWidth: 0.3,
        borderBottomColor: '#000'
    },
    dropdown: {
        flexDirection: 'row',
        paddingHorizontal: 5,
        paddingVertical: 0,
        alignItems: 'center',
        justifyContent: 'center',
    }
});

1 Ответ

0 голосов
/ 01 июня 2019

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

Вы просто делаете что-то вроде:

render(){
     this.state.brandsToCompare.map(brand => <PickerModalContainer brand={brand}/>)
}

Таким образом, главный Компонент будет отвечать только за управление, если пользователь выберет 1, 2 или любое количество марок или автомобилей, которые он хочет сравнить. PickerModalContainer будет иметь логику для извлечения, и в зависимости от того, что выберет пользователь, вы просто извлекаете и обновляете другие PickerModals. Таким образом, вы действительно не заботитесь о других сборщиках, так как они не «знают» друг друга.

Если в конце вам необходимо получить некоторую информацию для сравнения, вы можете предоставить функции в качестве реквизита, чтобы PickerModalContainer мог общаться с соответствующим PickerModal внизу и возвращать все, что вам нужно, из этого модального режима.

Я думаю, что это не так уж много изменений, если честно, просто какой-то рефакторинг.

...