1

It's about setState of an array.

React setstate is not replacing the array with new array

You can see that, I have customFieldsComponents in the constructor state.

In the addCustomField() function, I'm adding some elements in the array with the unique keys.

Now,In the removeCustomField() function, when I want to remove an element from the array, by setting new array of the filtered elements, its not replacing the customFieldsComponents array.

The problem is in the removeCustomField() function.

https://gist.github.com/akgarg007/ba8ade35b64b423def767fdfda263744

If you see the gist, I'm having issues on line number 98.


import React, { Component } from 'react';

// Import Custom Components
import TextField from '../CustomFieldComponents/TextField';
import DateField from '../CustomFieldComponents/DateField';
import RadioField from '../CustomFieldComponents/RadioField';

export const CustomFieldContext = React.createContext();

export class CustomFieldProvider extends Component {
    constructor(props) {
        super(props)
        this.state = {
            //  PhoneFieldCounter: 1,
            //  phoneComponents: [],
             customFieldSelected:'',
             customFieldsArray:[],
             customFieldsComponents:[],
        }
        this.addCustomField = this.addCustomField.bind(this);
        this.removeCustomField = this.removeCustomField.bind(this);
        this.handleCustomFieldChange = this.handleCustomFieldChange.bind(this);
    }
    addCustomField(){
        /***
         * Add all selected fields in the customFieldsArray array.
         * If custom field is already selected, it can't be selected again.
         * 
         * We can try to update the select dropdown list later on.  
         */    
        if(this.state.customFieldSelected.length == 0){
             // If no custom field selected!
            alert('Please select a field!');
            return NULL;
        }else if(this.state.customFieldSelected == 'Select'){
             // If no custom field selected!
            alert('Please select a field!');
            return NULL;
        }else{
            // check if field is already inserted in the addray or not
            var n = this.state.customFieldsArray.includes(this.state.customFieldSelected);    
            if(n != true){
                console.log(this.state.customFieldSelected);
                this.state.customFieldsArray.push(this.state.customFieldSelected);
            }else{
                // console.log(this.state.customFieldsArray);
                // console.log('field already selected, select another');
                alert('This field already selected, select another');
                return NULL;
            }
            // If selected field is a Text, then add new TextField in the custom Fields array
            if(
                this.state.customFieldSelected == 'PersonalID' ||
                this.state.customFieldSelected == 'Website' || 
                this.state.customFieldSelected == 'LinkedIn' ||
                this.state.customFieldSelected == 'Facebook' || 
                this.state.customFieldSelected == 'Twitter' || 
                this.state.customFieldSelected == 'Skype'
            ){
                var newField = (
                    <TextField key={this.state.customFieldSelected}  fieldName = {this.state.customFieldSelected} />
                );

            }else if(this.state.customFieldSelected == 'Birth Date'){
                var newField = (
                    <DateField key={this.state.customFieldSelected}  fieldName = {this.state.customFieldSelected} />
                );
            }
            else if(this.state.customFieldSelected == 'Gender'){
                const fieldNames = ['male','female'];
                var newField = (
                    <RadioField key={this.state.customFieldSelected}  fieldName = {this.state.customFieldSelected} fieldNames={fieldNames}  />
                );
            }
            else if(this.state.customFieldSelected == 'Decision Maker'){
                const fieldNames = ['yes','no'];
                var newField = (
                    <RadioField key={this.state.customFieldSelected}  fieldName = {this.state.customFieldSelected} 
                    fieldNames={fieldNames}  />
                );
            }
            this.setState(prevState => ({
                customFieldsComponents: [...prevState.customFieldsComponents, newField]
            }))
            // If selected field is a Textarea, then add new TextareaField in the custom Fields array
            // If selected field is a Radio, then add new RadioField in the custom Fields array
            // If selected field is a Dropdown, then add new DropdownField in the custom Fields array
        }

    }

    removeCustomField(fieldName){
        // First filter the field you want to remove from the array.
        // Then replace the old array with the new updated array. 

        var updatedCustomFieldComponents = this.state.customFieldsComponents.filter(element => element.key != fieldName);

        this.setState({ customFieldsComponents: [] }, console.log(this.state.customFieldsComponents))
        // this.setState({ customFieldsComponents: updatedCustomFieldComponents }, console.log(this.state.customFieldsComponents))
    }

    handleCustomFieldChange(field){
        this.setState({
            customFieldSelected: field
        });
    }

    render() {

        return (
            <CustomFieldContext.Provider 
                value={{
                    state:this.state,

                    addCustomField: this.addCustomField,
                    removeCustomField:(fieldName)=>{
                        this.removeCustomField(fieldName)
                    },
                    handleCustomFieldChange: (e)=>{
                        this.handleCustomFieldChange(e.target.value)
                    }
                }}
            >
                {this.props.children}
            </CustomFieldContext.Provider>         
        )
    }
}

Ashwani Garg
  • 1,479
  • 1
  • 16
  • 22

2 Answers2

4

The issue is you aren't using the setState callback correctly, it should be a function. As you've done, the log would fire immediately with the current state value, before it's been updated.

this.setState(
  { customFieldsComponents: [] }, 
  () => console.log(this.state.customFieldsComponents),
);

and

this.setState(
  { customFieldsComponents: updatedCustomFieldComponents },
  () => console.log(this.state.customFieldsComponents),
);
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
1

The second parameter of the setState is a callback, but you're just calling the console.log

change this

 this.setState({customFieldsComponents[]},console.log(this.state.customFieldsComponents))

to this

 this.setState({customFieldsComponents[]},() => console.log(this.state.customFieldsComponents))
Siraj Alam
  • 9,217
  • 9
  • 53
  • 65