Search code examples
reactjstypescriptsetstate

React updating nested arrayelement via setState


I'm trying to set state of input fields.

I want to update specific input value when a key is pressed.

setState state looks fine, but I'm getting error on map function of render part. (this.state.form[this.state.mode].form.map)

I don't understand why it breaks on map.

export type IMode = "login" | "forgot";
export interface IInput {
    value: string;
    error: string;
    id: string;
    name: string;
    placeholder: string;
    type: "text" | "password";
}
export interface IState {
    isRequestPending: boolean;
    backendError: string;
    mode: IMode;
    form: {
        [key in IMode]: {
            name: string;
            method: string;
            action: string;
            fields: IInput[];
        };
    };
}

in constructor 
       this.state = {
            isRequestPending: false,
            backendError: "",
            mode: "login",
            form: {
                login: {
                    name: "Login",
                    method: "",
                    action: "",
                    fields: [
                        {
                            value: "",
                            error: "",
                            id: "test",
                            placeholder: "Login",
                            type: "text",
                            name: "login"
                        }
                    ]
                },
                .... and so on

            }
        };
    private handleFormInput = (e, input: IInput, index) => {

        this.setState((prevState) => ({
            ...prevState,
            backendError: "",
            form: {
                ...prevState.form,
                [this.state.mode]: {
                    ...prevState.form[this.state.mode],
                       fields: {
                            ...prevState.form[this.state.mode].fields,
                           [index]: {
                                ...prevState.form[this.state.mode].fields[index],
                                value: "it Works, but map crash"
                           }
                       }
                }
            }
}


Solution

  • You are converting fields into an object which doesn't contain a map method. Update your state like this

    this.setState(prev =>({
       /*...*/
       fields : prev.form[this.state.mode].fields.map((field, i) =>{
           if(i !== index) return field
           return {
               ...field,
               value : 'foo'
           }
       })
    }))