React.js中FormControl无法更新状态值的问题排查
Hey there! Let's break down what's going wrong with your login component and fix it step by step.
What's Causing the Issue?
You've got two main problems here that are keeping your state from updating correctly:
Incorrect
onChangeEvent Parameters
React's form input components (including React Bootstrap'sFormControl) pass only a singleeventobject to theonChangecallback—there's no secondnewValueargument. Right now, you're trying to usenewValuewhich isundefined, so when you callsetState({email: newValue}), you're actually setting the state toundefined(which still matches your empty string check later).Premature Function Call in
catch
Your.catch(this.badInfosAlert('An error happend'))line is immediately running thebadInfosAlertfunction when the component mounts, not when an error is caught. That's because you're invoking the function directly instead of passing a callback.
Plus, while your onClick arrow function does bind this correctly for handleSubmit, we can clean that up too.
Step-by-Step Fixes
1. Fix the onChange Handlers
Update both FormControl elements to pull the input value from event.target.value instead of looking for a newValue parameter:
<FormControl type="email" onChange={(event) => this.setState({email: event.target.value})} placeholder="Email" /> <FormControl type="password" onChange={(event) => this.setState({password: event.target.value})} placeholder="Password" />
(Note: I also changed the email input's type to "email" for better native validation—optional but recommended!)
2. Fix the catch Callback
Replace your current catch block with an arrow function so the alert only runs when an error occurs:
.catch(() => this.badInfosAlert('An error happened'));
3. (Optional) Simplify this Binding
Instead of wrapping handleSubmit in an arrow function in the onClick, you can define handleSubmit as an arrow function directly in the class. This ensures this always refers to the component instance:
handleSubmit = (event) => { // Your existing handleSubmit code here }
Then update the Button to use the method directly:
<Button onClick={this.handleSubmit}>Login</Button>
Full Fixed Component Code
Here's the complete corrected component with all the fixes applied:
import React from 'react' import { login } from '../../api/Authentication' import { setStore } from '../../webapp/storage' import { Button, ControlLabel, Form, FormControl, FormGroup } from 'react-bootstrap'; export default class LoginPage extends React.Component { constructor(props){ super(props); this.state={ email:'', password:'' } } handleSubmit = (event) => { // Prevent default form submission behavior event.preventDefault(); if (this.state.email === '' || this.state.password === '') { const message = this.state.email === '' ? 'Email field empty' : 'Password field empty'; this.badInfosAlert(message); return; } console.log('-----------------------') console.log(this.state.email) console.log(this.state.password) const user = { email: this.state.email, password: this.state.password } console.log(JSON.stringify(user)) console.log('-----------------------') login(user).then(result => { if (result != null && result.status === 200) { setStore('token', result.json.user.token) } else { this.badInfosAlert(result.json.error) } }).catch(() => this.badInfosAlert('An error happened')); } badInfosAlert(message) { console.log(message); alert(message); } render() { return ( <div className='col-lg-12'> <Form onSubmit={this.handleSubmit}> <FormGroup controlId="formHorizontalEmail"> <ControlLabel>Email </ControlLabel> <FormControl type="email" value={this.state.email} // Add controlled input binding (optional but best practice) onChange={(event) => this.setState({email: event.target.value})} placeholder="Email" /> </FormGroup> <FormGroup controlId="formHorizontalPassword"> <ControlLabel>Password </ControlLabel> <FormControl type="password" value={this.state.password} // Add controlled input binding onChange={(event) => this.setState({password: event.target.value})} placeholder="Password" /> </FormGroup> <Button type="submit">Login</Button> </Form> </div> ) } }
I also added a couple of extra improvements:
event.preventDefault()inhandleSubmitto stop the browser from reloading the page when the form submits- Added
value={this.state.email}andvalue={this.state.password}to make the inputs fully controlled (this ensures the input always reflects the state value, which is a React best practice) - Changed the Button's
typeto"submit"and addedonSubmitto the Form instead of using a click handler—this is more semantic for form submissions
Quick Recap
- Always get input values from
event.target.valuein React formonChangehandlers - Never invoke callback functions directly in
.catch()—use an arrow function to delay execution - Use controlled inputs (bind the
valueprop to state) for predictable form behavior
内容的提问来源于stack exchange,提问作者Emixam23

