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.