首页 > 解决方案 > 使用 redux 表单字段数组超出更新深度

问题描述

我正在使用 Redux 表单字段数组,当向字段数组添加新元素时,应用程序由于以下错误而崩溃:

超过最大更新深度。当组件在 componentWillUpdate 或 componentDidUpdate 中重复调用 setState 时,可能会发生这种情况。React 限制了嵌套更新的数量以防止无限循环。

组件代码为:

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);

我认为当我执行以下行代码时会出现错误:

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

当我推送一个新值时,组件会无限地重新渲染。

我很惊讶,因为大部分字段数组代码都是从 redux 表单文档中复制的:

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

知道如何解决吗?

提前致谢。

标签: reactjsredux-form

解决方案


这部分代码是错误的

onSubmit={handleSubmit(onFormSubmit)}

改用箭头函数将解决问题:

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

当您在渲染函数中编写函数时(),在页面的每次渲染中,该函数都会调用并导致越来越多的状态更改。


推荐阅读