Deshan-Charuka
Deshan-Charuka

Reputation: 96

setState not working as expected in the form validations

I'm a bit new to react and I'm trying to implement a dynamic form with validation. where I get the input details from the backend and render the component according to that. All worked fine but when I tried to include form validation (when the user submitting the form I want to work the form validation) it didn't work at all. I tried with every solution on the web but didn't find anything to fix this issue. Can anyone give me help to fix this problem? Thanks!!

Here is my code

class Slider extends Component {
constructor(props) {
    super(props)
    const { providerConfigs } = this.props
    this.state = {
        hasError: false,
        inputs: [....]
    }
}

....

handleOnSubmit = () => {
    this.setState({ hasError: false })

    const { providerMappingActions: { addProvider }, history } = this.props;
    const { inputs } = this.state;

    inputs.forEach(input => {
        if (input.isRequired && input.attributeValue.length === 0) {
            this.setState({ hasError: true })
        }
        if (input.attributeOptionId == 5 && input.attributeValue.length !== 0) {
            if (input.attributeValue.length !== 10) {
                this.setState({ hasError: true })
            }

        }
    })

    if (!this.state.hasError) {
        const attributes = inputs.map(input => {
            return {
                attributeName: input.attributeName,
                attributeValue: input.attributeValue,
                isRequired: input.isRequired,
                attributeOptionId: input.attributeOptionId,
            }
        });
        console.log(attributes)
        this.resetInputs();
    }
}

render() {
    const { hasError, inputs } = this.state;

    return (
        <div>
            <div >
                <div >
                   ....
                                                            </FormGroup>)
                                                            : (
                                                                <FormGroup key={input.attributeOptionId}>
                                                                    <FormControl
                                                                        name={input.attributeName}
                                                                        type={this.checkType(input.fieldType)}
                                                                        autoFocus={!input.value}
                                                                        value={input.value}
                                                                        onChange={(e) => { this.handleChange(e) }}
                                                                        className={`${(hasError && input.isRequired && input.attributeValue.length === 0) ? 'validation-field-error' :
                                                                            hasError && input.attributeOptionId === 5 && input.attributeValue != '' && input.attributeValue.length !== 10 ? 'validation-field-error' : ''}`}
                                                                    />
                                                                </FormGroup>)
                                                        }
                                                    </td>
                                                </tr>
                                            );
                                        })
                                    }
                                    <tr>
                                        <td colSpan={2} align='right'>
                                            {
                                                inputs.map(input => {
                                                    if (hasError && input.isRequired && input.attributeValue.length === 0) {
                                                        return <div
                                                            key={input.attributeOptionId}
                                                        >
                                                            <label className='validation-error-text'><b>{input.attributeName} is required!</b></label>
                                                        </div>
                                                    } else if (hasError && input.attributeOptionId == 5 && input.attributeValue != '' && input.attributeValue.length !== 10) {
                                                        return <div
                                                            key={input.attributeOptionId}
                                                        >
                                                            <label className='validation-error-text'><b>Insert valid {input.attributeName}!</b></label>
                                                        </div>
                                                    }
                                                }
                                                )
                                            }
                                        </td>
                                    </tr>
                                </tbody>
                            </table>
                            <FormGroup>
                                <div >
                                    <div style={{ paddingLeft: "20px", paddingRight: "20px" }}>
                                        <button
                                           
                                           ...
                                </div>
                            </FormGroup>
                        </form>
                    </div>
                </div>
            </div>

        </div >

    )
}}

Please note that I have removed some of the code to increase readability.

Upvotes: 2

Views: 897

Answers (1)

Ross Allen
Ross Allen

Reputation: 44880

setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall.

https://reactjs.org/docs/react-component.html#setstate

Reading the state immediately after setting it will not guarantee the results you expect. Refactor to a local variable and set the state only once at the end of the function:

handleOnSubmit = () => {
    const hasError = false;
    const { providerMappingActions: { addProvider }, history } = this.props;
    const { inputs } = this.state;

    inputs.forEach(input => {
        if (input.isRequired && input.attributeValue.length === 0) {
            hasError = true;
        }
        if (input.attributeOptionId == 5 && input.attributeValue.length !== 0) {
            if (input.attributeValue.length !== 10) {
                hasError = true;
            }

        }
    })

    if (!hasError) {
        const attributes = inputs.map(input => {
            return {
                attributeName: input.attributeName,
                attributeValue: input.attributeValue,
                isRequired: input.isRequired,
                attributeOptionId: input.attributeOptionId,
            }
        });
        console.log(attributes)
        this.resetInputs();
    }

    // Set the state only once at the end of the function, this will
    // cause a re-render if the value changes.
    this.setState({ hasError });
}

Upvotes: 2

Related Questions