React Native Picker ArrayIndexOutOfBoundsExeception - PullRequest
0 голосов
/ 20 февраля 2020

Я использую Picker компонент от React Native.

У меня есть два компонента Picker: State (stateList() function) и City (cityList() function). Я вызываю два API: функция apiState() загружает список State и, основываясь на выбранном состоянии, функция apiCity(state_identification) отображает список City. ( фрагмент кода предоставлен ниже )

Код фрагмента :

    constructor(props) {
    super(props);
    this.state = {
        pickerValueState: null,
        dataState: [],

        pickerValueCity: null,
        dataCity: [],

        isLoading: true,
    }
}

componentDidMount() {
    this.apiState();
}

apiState() {
    let self = this;
    AsyncStorage.getItem('my_token').then((keyValue) => {
        axios({
            method: 'get',
            url: Constants.API_URL + 'user_c/cState/',
            responseType: 'json',
            headers: {
                'X-API-KEY': Constants.API_KEY,
                'Authorization': keyValue,
            },
        })
            .then(function (response) {
                console.log('Response State Data: ', response.data.state);
                self.setState({
                    dataState: response.data.state,
                    isLoading: false,
                });
            })
            .catch(function (error) {
                console.log('Error (1st): ', error);
            });
    }, (error) => {
        console.log('Error (2nd): ', error) //Display error
    });
}

apiCity(state_identification) {
    let self = this;
    AsyncStorage.getItem('my_token').then((keyValue) => {
        axios({
            method: 'post',
            url: Constants.API_URL + 'user_c/cCity/',
            data: {
                state_id: state_identification,
            },
            /*params: {
                state_id: state_identification,
            },*/
            responseType: 'json',
            headers: {
                'X-API-KEY': Constants.API_KEY,
                'Authorization': keyValue,
            },
        })
            .then(function (response) {
                console.log('Response City Data: ', response.data.all_city);
                self.setState({
                    pickerValueState: state_identification,
                    dataCity: response.data.all_city,
                    isLoading: false,
                });
            })
            .catch(function (error) {
                console.log('Error (1st): ', error);
            });
    }, (error) => {
        console.log('Error (2nd): ', error) //Display error
    });
}

stateList() {
    return (
        <View>
            <Text h4 h4Style={{ textAlign: 'center' }}>Select Location</Text>
            <Text h4 h4Style={styles.location}>State</Text>
            <View style={styles.pickerContainer}>
                <Picker
                    mode="dropdown"
                    selectedValue={this.state.pickerValueState}
                    //onValueChange={(itemValue, itemIndex) => this.setState({ pickerValueState: itemValue })}
                    onValueChange={(itemValue, itemIndex) => {
                        /*this.setState({ pickerValueState: itemValue },
                            () => {
                                this.apiCity(this.state.pickerValueState, itemValue);
                                console.log('State selected: ', (this.state.pickerValueState))
                            }
                        )*/
                        this.apiCity(itemValue)
                    }}
                >
                    {
                        this.state.dataState.map((item, key) => (
                            <Picker.Item label={item.state_desc} value={item.state} key={key} />)
                        )
                    }
                </Picker>
            </View>
        </View>
    );
}

cityList() {
    return (
        <View>
            <Text h4 h4Style={styles.location}>City</Text>
            <View style={styles.pickerContainer}>
                <Picker
                    mode="dropdown"
                    selectedValue={this.state.pickerValueCity}
                    onValueChange={(itemValue, itemIndex) => {
                        this.setState({ pickerValueCity: itemValue },
                            () => {
                                console.log('City selected: ', (this.state.pickerValueCity))
                            }
                        )
                    }}
                >
                    {
                        this.state.dataCity.map((item, key) => (
                            <Picker.Item label={item.city_desc} value={item.city} key={key} />)
                        )
                    }
                </Picker>
            </View>
        </View>
    );
}

render() {
    if (this.state.isLoading) {
        return (
            <View style={{ flex: 1, justifyContent: 'center' }}>
                <ActivityIndicator size="large" color="#0000ff" />
            </View>
        );
    } else {
        return (
            <View style={styles.container}>
                <View style={styles.locationContainer}>
                    {this.stateList()}
                    {this.cityList()}
                </View>
            </View>
        );
    }
}
}

Прежде чем продолжить, вот что данные JSON и отношение между State и City выглядит следующим образом:

//Lists of states:

{
    "state": [
        {
            "state": "14",
            "state_desc": "Kuala Lumpur"
        },
        {
            "state": "10",
            "state_desc": "Selangor"
        }
    ]
}

//if "state":"14" is selected, these cities are rendered in the picker
{
    "all_city": [
        {
            "city": "262",
            "city_desc": "Kuala Lumpur"
        },
        {
            "city": "263",
            "city_desc": "Sungai Besi"
        }
    ]
}

//if "state":"10" is selected, these cities are rendered in the picker
{
    "all_city": [
        {
            "city": "256",
            "city_desc": "Puchong"
        }
    ]
}

Я столкнулся с несколькими проблемами с моим кодом, а именно:

1. ArrayIndexOutOfBoundsExeception: length = 1; index = 1 ( снимок экрана представлен ниже ):

При выполнении этой последовательности приложение вылетает 100% времени:

  • выберите "state":"10"
  • , затем измените, чтобы выбрать "state":"14" и "city":"263"
  • , а затем, наконец, выберите "state":"10" снова

приложение сразу аварийно завершает работу.

enter image description here

2. Проблема с загрузкой значений :

При первоначальной загрузке приложения "state": "14" выбирается автоматически, НО средство выбора City остается пустым / не отображает метку.

Затем если я выбираю "state":"10", средство выбора City загружает значение "city": "256" (и показывает значение в файле console.log) и отображает метку "city_desc": "Puchong".

Однако, когда я выбираю "state": "14" снова, средство выбора City не загружает значение (не показывает значение в console.log), а только отображает метку "city_desc": "Kuala Lumpur". Загрузка значения начинается только после начала обмена между "city_desc": "Kuala Lumpur" и "city_desc": "Sungai Besi"

НАКОНЕЦ, когда я выбираю "state":"10" СНОВА, средство выбора City не загружает значение (не отображается значение в console.log), но отображается только метка "city_desc": "Puchong".

Наконец, Я пробовал следующее решение ( то есть key={item.length}) отсюда, но это не сработало.

1 Ответ

1 голос
/ 20 февраля 2020

с этим:

 this.setState({ pickerValueState: itemValue },
                        () => {
                            this.apiCity(this.state.pickerValueState);
                            console.log('State selected: ', (this.state.pickerValueState))
                        }
                    )

у вас есть период, когда у штата есть новый штат, но старый город. которые вызывают ваше исключение. попытаться установить состояние нового state в ответе API city. таким образом, вы устанавливаете новый штат и новый город одновременно. что, вероятно, означает, что вы должны передать функции apiCity новое состояние в качестве параметра, а затем использовать его в ответе API.

Так что в событии изменения просто выполните:

this.apiCity(this.state.pickerValueState, itemValue);

и в apiCityFunction, после выборки в setState для обоих вместе - города и штата:

 self.setState({
       pickerValueState: state,
       dataCity: response.data.all_city,
       isLoading: false,
 });
...