Search code examples
react-nativefor-loopsetstate

When i call setstate in a picker it changes the value two times


Im trying to render a form dynamically using "for" loop, and its renders good but when I tried to change the value in a picker, it changed but it immediately changes to the default value, so what i need to do to fix this?

class Datos extends Component {
    cotizadorData: any;
    planesData: any;
    dataStructure =
    {
        id: 1,
        name: '',
        lastName: '',
        email: '',
        documentNumber: '',
        dateOfBirth: '',
        age: '',
        gender: 'M',
        areaCode: '',
        phoneNumber: '',
        medicalObservation: 'Sin Observaciones'
    };
    emergencyContactDataStructure =
    {
        name: '',
        email: '',
        areaCode: '',
        phoneNumber: ''
    };
    planCode: string = '';
    departurePlaceCode: string = '';
    arrivalPlaceCode: string = '';
    passengersArray: Array = [];
    additionalPassengersCount: number = 0;
    additionalPassengersArray: Array = [];
    additionalPassengersView: Array = [];
    __isMounted: string = 'false';
    mainPassengerAreaCodeRef: any;
    emergencyContactAreaCodeRef: any;

    apiKey: string = '';
    xmlForOrder: string = '';

    constructor(){
        super();
        this.state = {
            showLoader: false,
            countries : [ {
                label: '',
                value: ''
            } ],
            holderData: this.dataStructure,
            additionalPassengers: [],
            additionalPassengersView: [],
            emergencyContact: this.emergencyContactDataStructure
        };
    }

    async componentDidMount () : void {

        this.setState({
            showLoader: true
        });
        await AsyncStorage.setItem('dataComponentIsMounted', 'true');
        this.apiKey = await AsyncStorage.getItem('apiKey');
        this.xmlForCountries = getCountries(this.apiKey);
        this.countries = await getOrbisDataServer(this.xmlForCountries);
        this.processCotizadorData();
        this.setState({
            departurePlace: this.countries[0].description
        });
        this.formatArraysForPickers();
    };

    updateAsyncStorage = async() => {
        this.__isMounted = await AsyncStorage.getItem('dataComponentIsMounted');
        if(!isUndefinedOrNull(this.__isMounted))
        {
            if(this.__isMounted === 'true')
            {
                this.processCotizadorData();
            }
        }
    };

    processCotizadorData = async() => {
        this.additionalPassengersCount = 0;
        this.additionalPassengersArray = [];
        this.cotizadorData = await AsyncStorage.getItem('cotizadorData');
        this.planesData = JSON.parse(await AsyncStorage.getItem('planesData'));
        if(!isUndefinedOrNull(this.cotizadorData))
        {
            this.cotizadorData = JSON.parse(this.cotizadorData);
            this.additionalPassengersCount = (this.cotizadorData.youngs + this.cotizadorData.adults +
                this.cotizadorData.semiSeniors + this.cotizadorData.seniors) - 1;
            let id = 2;
            for(let i = 0; i < this.additionalPassengersCount; i++)
            {
                this.additionalPassengersArray.push({
                    id: id,
                    name: '',
                    lastName: '',
                    email: '',
                    documentNumber: '',
                    dateOfBirth: '',
                    age: '',
                    gender: 'M',
                    areaCode: '',
                    phoneNumber: '',
                    medicalObservation: 'Sin Observaciones'
                });
                id++;
            }
            this.setState({
                additionalPassengers: this.additionalPassengersArray
            });
            this.renderAdditionalPassengersForms();
        }
    };

setAdditionalPassengerGender = (additionalPassenger, value) => {
        let additionalPassengersModified = [...this.state.additionalPassengers];
        let index = additionalPassengersModified.findIndex(el => el.id === additionalPassenger.id);
        additionalPassengersModified[index] = {...additionalPassengersModified[index], gender: value};
        this.setState({
            additionalPassengers: additionalPassengersModified
        });
    };

renderAdditionalPassengersForms = () => {

        for(let i = 0; i < this.additionalPassengersArray.length; i++)
        {
            this.additionalPassengersView.push(
                        <View>
                            <Text style={[styles.normalFont, styles.label]}>SEX</Text>
                            <Picker
                                selectedValue={this.state.additionalPassengers[i].gender}
                                style={{height: 50, width: 100}}
                                onValueChange={(value) => {this.setAdditionalPassengerGender (this.additionalPassengersArray[i], value)}}>
                                <Picker.Item label="Male" value="M"/>
                                <Picker.Item label="Female" value="F"/>
                            </Picker>
                        </View>
)
}this.setState({
            additionalPassengersView: this.additionalPassengersView
        });

}

I expect to change the picker value for selected one.

Edited: I added the whole component


Solution

  • Since your UI has no issue pilling up views on this.additionalPassengersView, I suppose renderAdditionalPassengersForms is not called everytime the value in any of the additional passengers pickers change.

    You problem is: selectedValue on Picker has to be updated when you make a choice. Otherwise, the picker will roll back to its non-updated selected value, as the behavior you describe.

    I use redux-form to manage my forms. But, assuming you don't want to use it, you can make a new component for the picker, putting the picker selected value on the state and updating this state on onValueChange callback