Search code examples
reactjsredux-form

Redux Form Async validation infinite recursion


I use [email protected] in my application. There is some fields where i need to define a validate function dynamically. Note that I need id and slice to look for the correct field in values

<Field
    component={SemanticFormField}
    as={Input}
    placeholder="From"
    name={"participation-card-" + id + "-slice-" + slice + "-min"}
    validate={[number]}
    />
<Field
    component={SemanticFormField}
    as={Input}
    placeholder="to"
    name={"participation-card-" + id + "-slice-" + slice + "-max"}
    validate={[number, validateMaxSlice(slice, id)]}
    />

When i define validateMaxSlice like this

const validateMaxSlice = (slice, id) => (value, values) => {
    const min = values["participation-card-" + id + "-slice-" + slice + "-min"];
    return min >= value ? "Invalid slice" : undefined;
};

Or inline like this

validate={[number, (value, values) => {
const min = values["participation-card-" + id + "-slice-" + slice + "-min"];
    return min >= value ? "Invalid slice" : undefined;}]

The application goes in an infinite loop the moment it renders the component.

The question is why and how to fix it ?

Edit:

Thank you for your help ! Here is how I implement it

Container part:

createSlice() {
    const id = uuidv4();
    return {
        id,
        validators: (value, values) => {
            const min = values["participation-card-" + this.props.id + "-slice-" + id + "-min"];
            return valSup(value, "Tranche incorrecte")(min);
        },
    };
}

addParticipationSlice() {
    let participationSlices = this.state.participationSlices;

    participationSlices.push(this.createSlice());

    this.setState({
        participationSlices,
    });
}

Scene part:

<Field
    component={SemanticFormField}
    as={Input}
    name={"participation-card-" + id + "-slice-" + slice.id + "-max"}
    size="mini"
    width={7}
    validate={[number, slice.validators]}
/>

Solution

  • As you are creating validators on the fly, it create a new validator instance every time it redraw.

    On the first redraw, React try to validate the value, then redraw to update the view. This, in turn, create a new validate function and change the related props value.

    As you change the props to the component, react will trigger a re-render of the Field. Thus causing it to revalidate again, causing again a re-render.

    One way to correct it is to generate one and only one version of each callback, reusing functions instances when appropriate.

    You can for example store a this.validators associative array then change your function generator to something like this:

    validateMaxSlice(slice, id) => {
         if (!this.validators[`${slice}-${id}`]) {
              this.validators[`${slice}-${id}`] = (value, values) => { ...Actual validation code... }
         }
         return this.validators[`${slice}-${id}`]
    }
    

    This way, validators are created on the fly but reused where they need to be.