绑定handleEmailError后提交报错:TypeError: this.setState is not a function
Hey Pedro, let's dig into this issue you're facing—so you've got a login form using redux-form's Field component for email, added a custom onChange handler (handleEmailError), and suddenly the submit throws a TypeError: this.setState is not a function? And removing that onChange fixes everything? Let's break down what's going on here.
The Root Cause
First off, it looks like you're using redux-form, and the problem is almost certainly tied to how you're overriding the Field component's default onChange behavior.
Redux-form's Field automatically passes an onChange callback to your custom Input component—this callback is responsible for syncing the field's value to redux's store. When you set onChange={this.handleEmailError} directly on the Field, you're replacing that default callback entirely. If your handleEmailError doesn't call the original redux-form onChange, you break the form's state management flow. This doesn't just prevent the email value from updating properly; it can also cause unexpected context issues (like this losing its reference to the component instance) in downstream logic like your onSubmit handler.
Even though you bound handleEmailError in the constructor, skipping the default onChange creates a chain reaction that messes up the form's internal state, which then surfaces as that setState error in your submit handler.
Fixes to Try
Let's walk through the most likely solutions:
1. Call the Default redux-form onChange in Your Handler
You need to keep redux-form's state sync working while adding your custom error logic. Modify your handleEmailError to accept and invoke the original onChange callback, then update your Field to pass it through:
First, update the handler:
handleEmailError(e, originalOnChange) { // Your custom error checking logic here const emailValue = e.target.value; // Example: Basic email format validation const hasError = !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailValue); // Update your component's error state this.setState({ error: hasError }); // Critical: Call the original redux-form onChange to sync the field value originalOnChange(e); }
Then adjust the Field component to pass the original onChange:
<Field component={Input} type="email" name="email" required={true} onChange={(e, fieldProps) => this.handleEmailError(e, fieldProps.onChange)} errorState={ this.state.error && (this.props.loginU.errorEmailMsg != null || this.props.loginU.errorMsg != null) } />
(Side note: I cleaned up your errorState condition to be more readable with parentheses—logically it's the same, but easier to parse.)
2. Check for Lost this in Nested Functions
If your handleEmailError uses nested async functions (like API calls or setTimeout), make sure you're not losing the component's this reference there. For example, this would break:
// ❌ Bad: Nested regular function loses `this` handleEmailError(e) { fetch('/validate-email', { method: 'POST', body: e.target.value }) .then(function(response) { // `this` here isn't your component instance! this.setState({ error: !response.ok }); }); }
Fix it with an arrow function (which inherits the parent's this):
// ✅ Good: Arrow function preserves `this` handleEmailError(e) { fetch('/validate-email', { method: 'POST', body: e.target.value }) .then((response) => { this.setState({ error: !response.ok }); }); }
3. Double-Check Your onSubmit Binding
While you're using an arrow function in handleSubmit(v => this.onSubmit(v)) (which should bind this correctly), it never hurts to confirm your onSubmit function is properly bound. If you haven't already, you can bind it in the constructor too:
constructor(props) { super(props); this.state = { loginMode: true, error: this.props.loginU.errorEmailMsg == null }; this.handleEmailError = this.handleEmailError.bind(this); this.onSubmit = this.onSubmit.bind(this); // Add this line }
Then simplify your form's onSubmit:
<form onSubmit={handleSubmit(this.onSubmit)}>
Quick Debugging Tip
To rule out this issues in handleEmailError immediately, add a console log at the start of the function:
handleEmailError(e) { console.log('Component instance:', this); // Should log your component object, not undefined // Rest of your logic }
If this logs undefined or something else, your binding is broken somewhere—but since you bound it in the constructor, this is unlikely unless you're doing something odd in the function itself.
Bonus: Consider Redux-Form's Built-in Validation
For form field validation, redux-form has built-in support via validate or asyncValidate functions that integrate better with its state management. Using those instead of a custom onChange handler can avoid these kinds of context issues entirely. But if you need the real-time error feedback that onChange provides, the first fix above should get you sorted.
内容的提问来源于stack exchange,提问作者Pedro Relvas

