如何根据 ReactJS 中的表单状态获取我的输入验证和 disabling/enabling 我的提交按钮

How to get my input validation and disabling/enabling my submit button depending on the state of the form in ReactJS

我正在使用 npm Validator 并尝试验证输入信息,然后根据验证更改提交地址按钮的状态。我现在设置它的方式我可以键入并且文本显示在控制台中而不是 UI 中。我不确定我有什么问题。该按钮也不会更改为 'enabled'。

组件如下:

import React, {Component} from 'react';
import { CardElement, injectStripe } from 'react-stripe-elements';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { clearCart } from '../actions/clearCartAction';
import getTotal from '../helpers/getTotalHelper';
import { Container, Col, Form, FormGroup, Input, Button } from 'reactstrap';
import './StripeCheckoutForm.css';
import validator from 'validator';

const cardElement = {
  base: {
    color: '#32325d',
    width: '50%',
    lineHeight: '30px',
    fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
    fontSmoothing: 'antialiased',
    fontSize: '18px',
    '::placeholder': {
      color: '#aab7c4'
    }
  },
  invalid: {
    color: '#fa755a',
    iconColor: '#fa755a'
  }
};

const FIREBASE_FUNCTION = 'https://us-central1-velo-velo.cloudfunctions.net/charge/';

// Function used by all three methods to send the charge data to your Firebase function
async function charge(token, amount, currency) {
  const res = await fetch(FIREBASE_FUNCTION, {
      method: 'POST',
      body: JSON.stringify({
          token,
          charge: {
              amount,
              currency,
          },
      }),
  });
  const data = await res.json();
  data.body = JSON.parse(data.body);
  return data;
}

class CheckoutForm extends Component {
  constructor(props) {
    super(props);
    this.submit = this.submit.bind(this);
  }

  state = {
    paymentComplete: false,
    firstName: '',
    lastName: '',
    address: '',
    city: '',
    prefecture: '',
    zipCode: '',
    email: '',
    submitDisabled: true
  }

  inputChangeHandler = (event, name) => {
    console.log('inputChange', name, event.target.value)
    event.preventDefault()
    this.setState({
      name: event.target.value
    }, console.log(this.state.submitDisabled), function(){ this.canSubmit() })
  }

  canSubmit = () => {
    console.log("canSubmit")
    const { firstName, lastName, address, city, prefecture,zipCode, email} = this.state
    if (validator.isAlpha(firstName) 
    && validator.isAlpha(lastName) 
    && address > 0
    && validator.isAlpha(city)
    && validator.isAlpha(prefecture)
    && zipCode > 0
    && validator.isEmail(email)) {
      this.setState({submitDisabled: false})
    } else {
      this.setState({submitDisabled: true})
    }
  }

  clearCartHandler = () => {
    console.log('clearCartHandler');
    this.props.onClearCart()
  }

  // User clicked submit
  async submit(ev) {
    console.log("clicked!")
    const {token} = await this.props.stripe.createToken({name: "Name"});
    const total = getTotal(this.props.cartItems);
    const amount = total; // TODO: replace with form data
    const currency = 'USD';
    const response = await charge(token, amount, currency);

    if (response.statusCode === 200) {
      this.setState({paymentComplete: true});
      console.log('200!!',response);
      this.clearCartHandler();

    } else {
      alert("wrong credit information")
      console.error("error: ", response);
    }
  }

  render() {

    if (this.state.complete) {
      return (
        <div>
          <h1 className="purchase-complete">Purchase Complete</h1>
          <Link to='/'>
            <button>Continue Shopping</button>
          </Link>
        </div>
      );
    }

    return ( 
      <div className="checkout-wrapper"> 
      <Container className="App">
        <h2 className='text-center'>Let's Checkout</h2>
          <Form className="form">
            <Col>
              <FormGroup>
                <Input
                  onChange= {this.inputChangeHandler}
                  type="first name"
                  name={"first name"}
                  value={this.state.firstName}
                  id="exampleEmail"
                  placeholder="first name"
                />
              </FormGroup>
            </Col>
            <Col>
              <FormGroup>
                <Input
                  onChange= {this.inputChangeHandler}
                  type="last name"
                  name="last name"
                  value={this.state.lastName}
                  id="exampleEmail"
                  placeholder="last name"
                />
              </FormGroup>
            </Col>
            <Col>
              <FormGroup>
                <Input
                  onChange= {this.inputChangeHandler}
                  type="address"
                  name="address"
                  value={this.state.adress}
                  id="exampleEmail"
                  placeholder="address"
                />
              </FormGroup>
            </Col>
            <Col>
              <FormGroup>
                <Input
                  onChange= {this.inputChangeHandler}
                  type="city"
                  name="city"
                  value={this.state.city}
                  id="exampleEmail"
                  placeholder="city"
                />
              </FormGroup>
            </Col>
            <Col>
              <FormGroup>
                <Input
                  onChange= {this.inputChangeHandler}
                  type="prefecture"
                  name="prefecture"
                  value={this.state.prefecture}
                  id="exampleEmail"
                  placeholder="prefecture"
                />
              </FormGroup>
            </Col>
            <Col>
              <FormGroup>
                <Input
                  onChange= {this.inputChangeHandler}
                  type="zipcode"
                  name="zipcode"
                  value={this.state.zipCode}
                  id="exampleEmail"
                  placeholder="zipcode"
                />
              </FormGroup>
            </Col>
            <Col>
              <FormGroup>
                <Input
                  onChange= {this.inputChangeHandler}
                  type="email"
                  name="email"
                  value={this.state.email}
                  id="exampleEmail"
                  placeholder="myemail@email.com"
                />
              </FormGroup>
            </Col>
            <Button className="save-address-button" disabled={this.state.submitDisabled}>Submit Address</Button>
            <div className="card-element">
            <CardElement style={cardElement}/>
            </div>
          </Form>
        <button className="checkout-button" disabled={false} onClick={this.submit}>Submit</button>
      </Container>
      </div> 
    );
  }
}

const mapStateToProps = state => {
  return {
    cartItems: state.shoppingCart.cartItems
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onClearCart: () => dispatch(clearCart())
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(injectStripe(CheckoutForm));

我认为该错误与误用this.setState的回调函数有关。

在您的 inputChangeHandler 方法中,您向 this.setState() 传递了三个参数,但是,this.setState() 希望您最多只传递两个参数,第二个参数是回调函数。

由于您将回调函数作为第三个参数传递,this.setState() 将默默地忽略它,因此不会调用您的验证方法。

另一个问题与inputChangeHandler 的名称参数有关,inputChangeHandler 将只接收事件对象,而不是名称。为了访问输入元素的名称属性,您需要通过 event.target.name

访问它

要解决问题,您可以将 inputChangeHandler 更改为

inputChangeHandler = event => {
    const { name, value } = event.target;
    console.log('inputChange', event.target.name, event.target.value)

    // notice the square bracket, this means we use the computed variable as 
    // the object key, instead of using the string 'name' as object key
    // also the name attribute in your Input element must match your state's key
    // use name='lastName' instead of name='last name' as your state's key is lastName
    this.setState({
      [name]: value
    }, this.canSubmit) // changing this line
}

如果你想保留你的 console.log(this.state.submitDisabled),你可以将它添加到你的验证方法中。

canSubmit = () => {
    console.log("canSubmit", this.state.submitDisabled) // add it here
    const { firstName, lastName, address, city, prefecture, zipCode, email} = this.state
    if (validator.isAlpha(firstName) 
    && validator.isAlpha(lastName) 
    && address > 0
    && validator.isAlpha(city)
    && validator.isAlpha(prefecture)
    && zipCode > 0
    && validator.isEmail(email)) {
      this.setState({submitDisabled: false})
    } else {
      this.setState({submitDisabled: true})
    }
}

在render方法中,我想你的意思是

if (this.state.paymentComplete)

而不是

if (this.state.complete)

此外,底部的按钮,您硬编码了禁用的属性值

<button
    className="checkout-button"
    disabled={false}
    onClick={this.submit}
>
    Submit
</button>

也许你的意思是

<button
    className="checkout-button"
    disabled={this.state.submitDisabled}
    onClick={this.submit}
>
    Submit
</button>

作为旁注,输入元素的类型属性应该是 'text'、'number'、'checkbox' 等...而不是像 [=51 这样的随机文本=] 或 'prefecture'