1

I'm using Redux Form Field Array and when adding a new element to fields array, the app crashes due the following error:

Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.

The component code is:

import React from 'react';
import {reduxForm, Field, FieldArray} from 'redux-form';

import { 
    Button,
    CircularProgress,
    Grid,
}from '@material-ui/core';
import {Link} from 'react-router-dom';
import { makeStyles } from '@material-ui/styles';

import {FileInput, SelectInput, LocationInput, TextInput } from './FormFields';
import { SERVICES } from '../Routing/routes';

const userStyles = makeStyles(theme=>({
    section:{
        maxWidth:theme.breakpoints.values.md,
        margin:'0 auto',

    },
    form:{
        position:'relative',
        paddingBottom:theme.spacing(8)
    },
    actionButtons:{
        position:'fixed',
        bottom:0,
        right:0,
        padding:theme.spacing(3),
        backgroundColor:theme.palette.secondary.main,
        borderTop: `1px solid ${theme.palette.primary.main}`
    },
    button:{
        marginLeft:theme.spacing(1)
    }
}));




const ProviderServiceForm = (props) =>{
    const classes = userStyles();
    const {handleSubmit, onFormSubmit, pending} = props;

    const renderSubmitIcon = () =>{
        if(pending)
            return <CircularProgress color="primary" size={20}/>
        else
            return  
    }

    const renderField = ({ input, label, type, meta: { touched, error } }) => (
        <div>
          <label>{label}</label>
          <div>
            <input {...input} type={type} placeholder={label} />
            {touched && error && <span>{error}</span>}
          </div>
        </div>
      );

    const renderVariants = ({ fields, meta: { error, submitFailed } }) =>(
        <ul>
            <li>
                <Button onClick={() => fields.push({})}>Añadir</Button>
                {submitFailed && error && <span>{error}</span>}
            </li>
            {fields.map((variant,index)=>(
                <li key={index}>
                    <h4>Variante #{index + 1}</h4>
                    <Field
                        name={`${variant}.title`}
                        type="text"
                        component={renderField}
                        label="First Name"
                    />
                </li>
            ))}
        </ul>
    );


    return(
        <div className={classes.section}>
            <form onSubmit={handleSubmit(onFormSubmit)} className={classes.form}>
                <input type="hidden" value="something"/>
                <FieldArray name="variants" component={renderVariants}/>
                <Field name="placeName" label="Nombre del centro o del lugar" component={TextInput} autoComplete="organization"/>
                <Field name="address" label="Dirección" component={LocationInput} autoComplete="off"/>
                <Field name="adressDetails" label="Planta, Piso, Puerta..." component={TextInput} autoComplete="address-level3"/>
                <Field name="category"  label="Categoría de servicios" component={SelectInput} autoComplete="category"/>
                <Field name="image" type="file" label="Sube una foto..." component={FileInput}/>
                <Grid container className={classes.actionButtons} justify="flex-end">
                    <Link to={SERVICES} style={{ textDecoration: 'none' }}>
                        <Button type="submit" variant="outlined" color="primary" disabled={pending}>Cancelar</Button>
                    </Link>
                    <Button type="submit" variant="contained" color="primary" className={classes.button} disabled={pending} startIcon={renderSubmitIcon()}>Guardar</Button>
                </Grid>
            </form>
        </div>
    )
}

const validate = (formValues) =>{
    const errors = {}

    if (!formValues.variants || !formValues.variants.length) {
        errors.variants = { _error: 'Almenos tienes que introducir una variante' };
      } else {
        const variantsArrayErrors = [];
        formValues.variants.forEach((variant, variantIndex) => {
          const variantErrors = {};
          if (!variant || !variant.title) {
            variantErrors.title = 'Tienes que introducir un título';
            variantsArrayErrors[variantIndex] = variantErrors;
          }
          if (!variant || !variant.price > 0) {
            variantErrors.price = 'Tienes que poner un precio superior a 0€';
            variantsArrayErrors[variantIndex] = variantErrors;
          }
        });
        if (variantsArrayErrors.length) {
            errors.variants = variantsArrayErrors;
        }
    }
    if (!formValues.placeName){
        errors.placeName = 'Debes intriducir el nombre del centro o lugar'
    }
    if (!formValues.address){
        errors.address = 'Debes intriducir una dirección válida'
    }
    if(!formValues.category){
        errors.category = 'Tienes que seleccionar una categoría';
    }
    if(!formValues.image){
        errors.image = 'Debes seleccionar una imagen de Portada';
    }

    return errors;
}


export default reduxForm({
    form:'ProviderServiceForm',
    validate,
})(ProviderServiceForm);

I think the error comes when I execute the following line code:

<Button onClick={() => fields.push({})}>Añadir</Button>

When I push a new value, the component re-renders infinetly.

I'm surprised as most of the Field Array code was copied from redux form documentation:

https://redux-form.com/8.3.0/examples/fieldarrays/

Any idea how to fix it?

Thanks in advance.

1
  • Did you find any solution? I am struggling with the very same issue Commented Nov 23, 2020 at 23:45

1 Answer 1

1

this part of code is wrong

onSubmit={handleSubmit(onFormSubmit)}

use arrow function instead will fix the issue:

onSubmit={() => handleSubmit(onFormSubmit)}

when you write a function with () in the render function, in every render of the page the function will call and cause changing the state more and more.

Sign up to request clarification or add additional context in comments.

1 Comment

You're right @2 8. But even writting () the component ends in a loop with the same error. It has to be something else :(

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.