我创建了一个登录页面,它将用户从公共路由到经过身份验证的路由运行良好。如果登录时出错(例如找不到电子邮件),我会在控制台Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the LoginForm component.
中收到错误消息。
我认为这可能与我在App
中使用createContainer的方式有关。
我认为问题与流星在从服务器收到回复之前通过Meteor.loggingIn();
等于true
的方式有关。如果出现错误,true
会快速更改为false
,我认为这会导致页面重新加载。
我希望能够使用this.setState({ loginError: error.reason });
,以便告诉用户出了什么问题。
任何建议。
路径:App.jsx
const App = appProps => (
<Router>
<Grid className="main-page-container">
<Switch>
<Authenticated exact path="/" component={Home} {...appProps} />
<Public exact path="/login" component={Login} {...appProps} />
</Switch>
</Grid>
</Router>
);
App.propTypes = {
loggingIn: PropTypes.bool,
authenticated: PropTypes.bool
};
export default createContainer(() => {
const loggingIn = Meteor.loggingIn();
return {
loggingIn,
authenticated: !loggingIn && !!Meteor.userId()
};
}, App);
路径:Public.jsx
const Public = ({ loggingIn, authenticated, component, ...rest }) => (
<Route
{...rest}
render={(props) => {
if (loggingIn) return <div />;
return !authenticated ?
(React.createElement(component, { ...props, loggingIn, authenticated })) :
(<Redirect to="/" />);
}}
/>
);
Public.propTypes = {
loggingIn: PropTypes.bool,
authenticated: PropTypes.bool,
component: PropTypes.func
};
export default Public;
路径:LoginForm.jsx
export default class LoginForm extends React.Component {
constructor(props) {
super(props);
this.state = {
email: '',
errors: {},
password: '',
loginError: ''
};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox'
? target.checked
: target.value;
const name = target.name;
this.setState({[name]: value});
}
handleSubmit(event) {
event.preventDefault();
this.setState({
errors: {}
}, function() {
var data = {
email: this.state.email,
password: this.state.password
};
var email = this.state.email;
var password = this.state.password;
const errors = loginUserValidation(data);
if (errors) {
this.setState({errors: errors});
} else {
Meteor.loginWithPassword(email, password, (error) => {
if (error) {
this.setState({ loginError: error.reason });
}
});
}
});
}
render() {
return (
<div className="registration-form-container">
<Row>
<Col sm={8} smOffset={2} md={6} mdOffset={3}>
<div className="paper">
<Form onSubmit={this.handleSubmit}>
<section className="form-title">
<h3 className="text-center">Login</h3>
</section>
<hr />
<section className="form-content-login-or-registration">
{this.state.loginError &&
<div className="alert alert-danger">
<p>{this.state.loginError}</p>
</div>
}
<SingleInput
name={'email'}
inputType={'email'}
controlFunc={this.handleInputChange}
content={this.state.email}
placeholder={'Email'}
bsSize={null}
error={this.state.errors && this.state.errors.email}
/>
<SingleInput
name={'password'}
inputType={'password'}
controlFunc={this.handleInputChange}
content={this.state.password}
placeholder={'Password'}
bsSize={null}
error={this.state.errors && this.state.errors.password}
/>
</section>
<section className="form-buttons">
<Button type="submit" className="btn btn-primary" block>Login</Button>
</section>
</Form>
</div>
</Col>
</Row>
</div>
)
}
}
答案 0 :(得分:2)
当Meteor.loginWithPassword
将logginIn
值更改为true时,您的<Public />
组件会卸载已包裹的<LoginForm />
const Public = ({ loggingIn, authenticated, component, ...rest }) => (
<Route
{...rest}
render={(props) => {
if (loggingIn) return <div />; // <--- this right here
return !authenticated ?
(React.createElement(component, { ...props, loggingIn, authenticated })) :
(<Redirect to="/" />);
}}
/>
);
因此loggingIn
值更改导致<Public />
重新呈现。现在loggingIn
为真,你渲染一个div而不是组件,卸载它并在错误回调试图调用它时使setState
不可用。
编辑:回应你的评论......
为了防止这种情况,您可以处理<LoginForm />
if (loggingIn) return <div />;
组件中的<Route />
移除<Public />
。<LoginForm />
内,您可以处理错误情况。通过制作一个显示错误的组件并将其包含在您希望显示的<LoginForm />
组件中来执行此操作。如果没有错误,则使<ErrorDisplay />
组件不返回任何内容。示例<ErrorDisplay />
组件
const ErrorDisplay = ({ errors }) => {
errors && <div className="error-container">{ errors }</div>
};
这显然是准系统,但我希望它能帮助你理解!