簡體   English   中英

在我的 React 應用程序中,我在哪里處理服務器返回的表單驗證錯誤?

[英]Where do I handle form validation errors returned by the server in my React app?

我正在使用 React 16.12.0。 我試圖弄清楚如何處理和顯示從我的服務器返回的驗證錯誤。 我有這個表格設置...

import React, {Component} from 'react';
import {FormControl, FormGroup} from 'react-bootstrap';

/* Import Components */
import Input from '../components/Input';
import Country from '../components/Country';
import Province from '../components/Province';
import Button from '../components/Button'

class FormContainer extends Component {
  statics: {
    DEFAULT_COUNTRY: 484;
  }

  constructor(props) {
    super(props);

    this.state = {
      countries: [],
      provinces: [],
      newCoop: {
        name: '',
        type: {
          name: ''
        },
        address: {
          formatted: '',
          locality: {
            name: '',
            postal_code: '',
            state: ''
          },
          country: 484, //FormContainer.DEFAULT_COUNTRY,
        },
        enabled: true,
        email: '',
        phone: '',
        web_site: ''
      },

    }
    this.handleFormSubmit = this.handleFormSubmit.bind(this);
    this.handleClearForm = this.handleClearForm.bind(this);
    this.handleInput = this.handleInput.bind(this);
  }

  /* This life cycle hook gets executed when the component mounts */

  handleFormSubmit(e) {
    e.preventDefault();
    const NC = this.state.newCoop;
    delete NC.address.country;

    fetch('/coops/',{
        method: "POST",
        body: JSON.stringify(this.state.newCoop),
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
      }).then(response => {
        response.json().then(data =>{
          console.log("Successful" + data);
        })
    })
  }
  handleClearForm() {
    // Logic for resetting the form
  }
  handleInput(e) {
    let self=this
    let value = e.target.value;
    console.log("value:" + value);
    let name = e.target.name;
    //update State
    this.setValue(self.state.newCoop,name,value)
  }

  setValue = (obj,is, value) => {
       if (typeof is == 'string')
         return this.setValue(obj,is.split('.'), value);
       else if (is.length === 1 && value!==undefined)
         return this.setState({obj: obj[is[0]] = value});
       else if (is.length === 0)
         return obj;
       else
         return this.setValue(obj[is[0]],is.slice(1), value);
  }

  render() {
    return (
        <form className="container-fluid" onSubmit={this.handleFormSubmit}>
            <FormGroup
 controlId="formBasicText">

                <Input inputType={'text'}
                   title= {'Name'}
                   name= {'name'}
                   value={this.state.newCoop.name}
                   placeholder = {'Enter cooperative name'}
                   handleChange = {this.handleInput}

                   /> {/* Name of the cooperative */}

                <Input inputType={'text'}
                   title= {'Type'}
                   name= {'type.name'}
                   value={this.state.newCoop.type.name}
                   placeholder = {'Enter cooperative type'}
                   handleChange = {this.handleInput}

                   /> {/* Type of the cooperative */}

                <Input inputType={'text'}
                   title= {'Street'}
                   name= {'address.formatted'}
                   value={this.state.newCoop.address.formatted}
                   placeholder = {'Enter address street'}
                   handleChange = {this.handleInput}

                   /> {/* Address street of the cooperative */}

                <Input inputType={'text'}
                   title= {'City'}
                   name= {'address.locality.name'}
                   value={this.state.newCoop.address.locality.name}
                   placeholder = {'Enter address city'}
                   handleChange = {this.handleInput}

                   /> {/* Address city of the cooperative */}

              <Country title={'Country'}
                  name={'address.country'}
                  options = {this.state.countries}
                  value = {this.state.newCoop.address.country}
                  placeholder = {'Select Country'}
                  handleChange = {this.handleInput}
                  /> {/* Country Selection */}

              <Province title={'State'}
                  name={'address.locality.state'}
                  options = {this.state.provinces}
                  value = {this.state.newCoop.address.locality.state}
                  placeholder = {'Select State'}
                  handleChange = {this.handleInput}
                  /> {/* State Selection */}

              <Input inputType={'text'}
                   title= {'Postal Code'}
                   name= {'address.locality.postal_code'}
                   value={this.state.newCoop.address.locality.postal_code}
                   placeholder = {'Enter postal code'}
                   handleChange = {this.handleInput}

                   /> {/* Address postal code of the cooperative */}

              <Input inputType={'text'}
                   title= {'Email'}
                   name= {'email'}
                   value={this.state.newCoop.email}
                   placeholder = {'Enter email'}
                   handleChange = {this.handleInput}

                   /> {/* Email of the cooperative */}

              <Input inputType={'text'}
                   title= {'Phone'}
                   name= {'phone'}
                   value={this.state.newCoop.phone}
                   placeholder = {'Enter phone number'}
                   handleChange = {this.handleInput}

                   /> {/* Phone number of the cooperative */}

              <Input inputType={'text'}
                   title= {'Web Site'}
                   name= {'web_site'}
                   value={this.state.newCoop.web_site}
                   placeholder = {'Enter web site'}
                   handleChange = {this.handleInput}

                   /> {/* Web site of the cooperative */}


              <Button
                  action = {this.handleFormSubmit}
                  type = {'primary'}
                  title = {'Submit'}
                  style={buttonStyle}
              /> { /*Submit */ }

              <Button
                  action = {this.handleClearForm}
                  type = {'secondary'}
                  title = {'Clear'}
                  style={buttonStyle}
              /> {/* Clear the form */}

            </FormGroup>
        </form>
    );
  }

  componentDidMount() {
    let initialCountries = [];
    let initialProvinces = [];
    // Get initial countries
    fetch('/countries/')
        .then(response => {
            return response.json();
        }).then(data => {
        initialCountries = data.map((country) => {
            return country
        });
        console.log("output ...");
        console.log(initialCountries);
        this.setState({
            countries: initialCountries,
        });
    });
    // Get initial provinces (states)
    fetch('/states/484/')
        .then(response => {
            return response.json();
        }).then(data => {
        console.log(data);
        initialProvinces = data.map((province) => {
            return province
        });
        this.setState({
            provinces: initialProvinces,
        });
    });
  }
}

const buttonStyle = {
  margin : '10px 10px 10px 10px'
}

export default FormContainer;

當服務器(一個 Django Python 應用程序)無法處理表單時,它會返回一個 400 響應正文,其中包含鏈接到每個字段的錯誤。 例如,這樣的響應主體看起來像

{"phone":["The phone number entered is not valid."]}

捕獲此錯誤並將其顯示在我的表單中的正確方法是什么? 我見過的所有示例都在提交表單之前處理驗證——例如,在它結束之前編寫“validateFields”方法,或在“handleFormSubmit”處理程序中編寫類似的東西。

編輯:添加了新的 fetch 方法以響應評論。 但是,當獲取請求返回 400 時,添加“catch”塊不會顯示錯誤。

fetch('/coops/',{
    method: "POST",
    body: JSON.stringify(this.state.newCoop),
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
}).then(response => {
    response.json().then(data =>{
        console.log("Successful" + data);
    })
}).catch(error => console.log(error))

CHrome 開發控制台在請求上報告 400 以及

FormContainer.jsx:54 Fetch failed loading: POST "http://localhost:3000/coops/".

此外,盡管有 400 和 Chrome 報告的內容,但仍會打印出“成功”console.log 消息。

處理表單提交錯誤響應。

fetch('/coops/',{
  method: "POST",
  body: JSON.stringify(this.state.newCoop),
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  },
}).then(response => {
  // check if received an OK response, throw error if not
  if (response.ok) {
    return response.json();
  }
  throw new Error(response.statusText);        
}).then(jsonData => {
  console.log("Successful", jsonData);
}).catch(errors => {
  // If error was thrown then unpack here and handle in component/app state
  console.log('error', errors);
  this.setState({ errors });
});

顯示一個簡單的錯誤列表(假設所有錯誤都是形狀{[string]: arrayOf(string)}

render() {
  const errors = Object.values(this.state.errors);
  return (
    <form
      className="container-fluid"
      onSubmit={this.handleFormSubmit}
    >
      <FormGroup controlId="formBasicText">

        {errors.length && (
          <ul>
            {errors.map(error => <li>{error.join(" ")}</li>}
          </ul>
        )}

        <Input
          inputType={'text'}
          title= {'Name'}
          name= {'name'}
          value={this.state.newCoop.name}
          placeholder = {'Enter cooperative name'}
          handleChange = {this.handleInput}
        /> {/* Name of the cooperative */}
        ...

顯示字段級錯誤

render() {
  const { errors } = this.state;
  return (
    <form
      className="container-fluid"
      onSubmit={this.handleFormSubmit}
    >
      <FormGroup controlId="formBasicText">

        <Input
          inputType={'text'}
          title= {'Name'}
          name= {'name'}
          value={this.state.newCoop.name}
          placeholder = {'Enter cooperative name'}
          handleChange = {this.handleInput}
        /> {/* Name of the cooperative */}
        {errors.name && (
          <div className="fieldError">
            {error.name.join(" ")}
          </div>
        )}

        <Input
          inputType={'text'}
          title= {'Type'}
          name= {'type.name'}
          value={this.state.newCoop.type.name}
          placeholder = {'Enter cooperative type'}
          handleChange = {this.handleInput}
        /> {/* Type of the cooperative */}
        {errors.name && (
          <div className="fieldError">
            {error['type.name"].join(" ")}
          </div>
        )}
        ...

后者是一種常見的模式,許多表單庫直接將表單錯誤作為道具,並自行處理顯示錯誤幫助文本。 許多處理兩者的形式,使用保留的表單級錯誤鍵,即_error ,然后是所有字段級錯誤,它們使用字段名稱作為它們的鍵。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM