【问题标题】:ReactJS - setState in parent component submits form despite using preventDefault()ReactJS - 尽管使用了 preventDefault(),但父组件中的 setState 仍会提交表单
【发布时间】:2021-07-28 13:40:53
【问题描述】:

我试图在验证表单时显示警报。问题是当验证期间发生错误时,我想显示在父组件中定义的警报 - 这会导致提交/重新加载表单,并且 e.preventDefault() 不足以停止提交。我发现 props 传递的 setState 会导致提交,但我不知道如何设置状态并阻止提交。这个案子我能做什么?我想 React Router Dom 有一些共同点,因为这种机制在不使用路由的情况下工作。这是一些代码:

App.js(父组件)

import React, { Fragment, Component } from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import { Alert } from "react-bootstrap";
import Login from "./components/pages/Login";
import Home from "./components/pages/Home";
class App extends Component {
    state = {
        alert: "",
    };
    render() {
        const { alert } = this.state;
        return (
            <Fragment>
                <Router>
                    {alert && <Alert variant="danger">{alert}</Alert>}
                    <Switch>
                        <Route exact path="/" component={() => <Home />} />
                        <Route exact path="/login" component={() => <Login onShowAlert={(alert) => this.setState({ alert: alert })} />} />
                    </Switch>
                </Router>
            </Fragment>
        );
    }
}
export default App;

Login.js(子组件)

import React, { Component, Fragment } from "react";
import { Form, Button } from "react-bootstrap";
class Login extends Component {
    state = {
        login: "",
        password: "",
    };
    handleCheckValidation = (e) => {
        e.preventDefault();
        const { onShowAlert } = this.props;
        onShowAlert("Show some error message"); //this causes submitting form
    };
    render() {
        const { login, password } = this.state;
        return (
            <Fragment>
                <Form onSubmit={this.handleCheckValidation} autoComplete="off">
                    <Form.Control type="email" name="login" value={login} onChange={(e) => this.setState({ [e.target.name]: e.target.value })}></Form.Control>
                    <Form.Control type="password" name="password" value={password} onChange={(e) => this.setState({ [e.target.name]: e.target.value })}></Form.Control>
                    <Button type="submit" variant="primary">Sign in</Button>
                </Form>
            </Fragment>
        );
    }
}
export default Login;

【问题讨论】:

  • this causes submitting form 但它 (onShowAlert) 已经在提交处理程序中。所以提交处理程序按预期工作。我认为这里的问题是您的表单与路由器一起被重新渲染,因为App 中的状态发生了变化。

标签: reactjs react-router-dom


【解决方案1】:

问题

对于给定的处理程序:

handleCheckValidation = (e) => {
  e.preventDefault();
  const { onShowAlert } = this.props;
  onShowAlert("Show some error message");
};

我没有看到提交表单的方法。

我认为问题在于如何在 Route 中呈现 Login 组件。

<Route
  exact
  path="/login"
  component={() => (
    <Login onShowAlert={(alert) => this.setState({ alert: alert })} />
  )}
/>

Route component

当你使用组件(而不是渲染或子,下面) 路由器使用React.createElement 从 给定的组件。这意味着如果您向 组件道具,您将在每次渲染时创建一个新组件。这 导致现有组件卸载和新组件 安装而不是仅仅更新现有组件。使用时 用于内联渲染的内联函数,使用 render 或 儿童道具。

this.state.alert 状态已更新,App 已重新呈现。

解决方案

Routerender 属性上渲染组件:

<Route
  exact
  path="/login"
  render={() => (
    <Login onShowAlert={(alert) => this.setState({ alert: alert })} />
  )}
/>

或作为子组件:

<Route
  exact
  path="/login"
>
  <Login onShowAlert={(alert) => this.setState({ alert: alert })} />
</Route>

您还想继续修复您的回家路线。这仍然可以使用 component 道具,因为您没有注入额外的道具。

<Route exact path="/" component={Home} />

【讨论】:

  • 不是 OP,但感谢您的精彩解释。是否曾经有过使用组件而不是渲染或子级更好的时候?
  • @Hyetigran 是的,基本上当你不需要传递任何额外的道具时(请参阅我关于回家路线的回答中的最后一个编辑)。
  • 是的,将“组件”道具更改为“渲染”解决了问题。感谢您的解决方案和解释!我会用 Home 组件做同样的事情:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-26
  • 2021-02-12
相关资源
最近更新 更多