简体   繁体   中英

How to send POST request from React form using axios?

Here is something like a CRUD using React and axios. I have some component with form and inputs. The form recieved data from express backend using axios GET method, and semingly there is no problems. But the second task is to change data in inputs and post to the route using axios POST. For some reason it fails to collect the data from all inputs to json for the POST request. Someone tell me what is wrong here?

The JSON requested from backend looks like this:

{
    "data": [
        {
            "_id": "5d28a6fcec97b111c2f5867d",
            "phone": "+1 (111) 111 11 11",
            "email": "shutruk@gmail.com",
            "title": "khkjhkjhkj",
            "longTitle": "lkjlkjlkjlk",
            "introTitle": "Shutruk",
            "introLongTitle": "Shutruk-Nahhunte",
            "videoLink": "khkjhkjhkj",
            "introText": "lkjlkjlkjlk",
            "__v": 0
        }
    ]
}

Here is the component:

import React, { Component } from 'react';
import axios from 'axios';

class Misc extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: [],
      value: [],
      loading: true,
      error: false,
    };
    this.handleSubmit = this.handleSubmit.bind(this);
  }  
  onChange(e) {
    this.setState({ value: e.target.value });
  }
  componentDidMount() {
    axios.get('http://localhost:5555/data')
      .then(res => {
        const data = res.data.data; // get the data array instead of object
        this.setState({ data, loading: false });
      })
      .catch(err => { // log request error and prevent access to undefined state
        this.setState({ loading: false, error: true });
        console.error(err); 
      })
  }
  handleSubmit(e) {
    e.preventDefault();

    const data = {
      value: this.state.value
    };

    axios.post('http://localhost:5555/data', { data })
      .then(res => {
        console.log(data);
      })
  }
  render() {
    if (this.state.loading) {
      return(
        <div>
          <p> Loading... </p>
        </div>
      )
    }
    if (this.state.error || !this.state.data[0]) { // if request failed or data is empty don't try to access it either
      return(
        <div>
          <p> An error occured </p>
        </div>
      )
    }
    return (
      <form action="" onSubmit={this.handleSubmit}>
        <h2 className="center" >Change values</h2>
        <div className="center"><img src={require('../img/orn.png')} alt="" className="orn"/></div>
        <h5>Phone:</h5>
        <input type="text" name="phone" defaultValue={ this.state.data[0].phone } onChange={e => this.onChange(e)} />
        <h5>Email:</h5>
        <input type="text" name="email" defaultValue={ this.state.data[0].email } onChange={e => this.onChange(e)} />
        <h5>Title:</h5>
        <input type="text" name="title" defaultValue={ this.state.data[0].title } onChange={e => this.onChange(e)} />
        <h5>Description:</h5>
        <input type="text" name="longTitle" defaultValue={ this.state.data[0].longTitle } onChange={e => this.onChange(e)} />
        <h2 className="center" >Intro:</h2>
        <div className="center"><img src={require('../img/orn.png')} alt="" className="orn"/></div>
        <h5>Title:</h5>
        <input type="text" name="introTitle" defaultValue={ this.state.data[0].introTitle } onChange={e => this.onChange(e)} />
        <h5>Description:</h5>
        <input type="text" name="introLongTitle" defaultValue={ this.state.data[0].introLongTitle } onChange={e => this.onChange(e)} />
        <h5>Link to video:</h5>
        <input type="text" name="videoLink" defaultValue={ this.state.data[0].videoLink } onChange={e => this.onChange(e)} />        
        <h5>Text:</h5>
        <textarea name="introText" id="" cols="30" rows="10" defaultValue={ this.state.data[0].introText } onChange={e => this.onChange(e)}></textarea>
        <button type="submit" className="btn-large waves-effect waves-light xbutton">Save</button>
      </form>
    );
  }
}

export default Misc;

By looking at this.setState({ value: e.target.value }); , every change on the inputs will set a new value to the only state.value property overwriting previous value.

I think you should modify onChange to

onChange(e) {
     this.setState({[e.target.name]: e.target.value})
} 

On submit, in your handleSubmit you will have the values as:

const data = {
  phone: this.state.phone,
  email: this.state.email, 
  title: this.state.title,
 // same for other inputs .. 
};

This updates the property in the state having the same name as the corresponding input.

I would recommed to use FormData to keep all the form data clean and iterable, once you have submited your form, data goes to the event submit and becomes easier to use.

Using the FormData API :

    const formData = new FormData(event.target)

This way it becomes easier and cleaner to create an object to work with.

formData returns and FormData Object witch is iterable.

    const body = {}
    formData.forEach((value, property) => body[property] = value)

So now that you have built a new object you can update, delete, add, encrypt, or wharever you want it's properties and/or values.

Also there is not need to use a function to handle changes on inputs with the onChange method since HTML does it for you natively , just use defaultValue="" and required atributes to keep your inputs filled in all of your fields.

Sometimes HTML is just enought for the work we want :)

Here is a little example of all said above.

import React from 'react';

export default class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      //no needed.
    }
  }

  onSubmitForm = e => {
    e.preventDefault()
    const formData = new FormData(e.target)
    const body = {}
    formData.forEach((value, property) => body[property] = value)
    //here you can update, remove, add values/properties in the body object this is specially usefull if any custom process must be done to check, encrypt data or wherever you want.
    console.table(body)
    // Request goes here.
  }

  render() {
    return (
      <div className="App">
        <form onSubmit={e => this.onSubmitForm(e)}>
          <input name="name" type="text" defaultValue="" required />
          <input name="lastname" type="text" defaultValue="" required />
          <button type="submit">submit</button>
        </form>
      </div>
    )
  }
}

If you want to learn more about how to handle errors in React please have a look of Error Boundaries .

It's OK! Here is working code. To initialaize the correct POST request, I use the if operator:

import React, { Component } from 'react';
import axios from 'axios';

class Misc extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: [],
      value: [],
      loading: true,
      error: false,
    };
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  onChange(e) {
    this.setState({ [e.target.name]: e.target.value })
  }
  componentDidMount() {
    axios.get('http://localhost:5555/data')
      .then(res => {
        const data = res.data.data; // get the data array instead of object
        this.setState({ data, loading: false });
      })
      .catch(err => { // log request error and prevent access to undefined state
        this.setState({ loading: false, error: true });
        console.error(err);
      })
  }
  handleSubmit(e) {
    e.preventDefault();

    const data = {
      phone: this.state.phone ? this.state.phone : this.state.data[0].phone,
      email: this.state.email ? this.state.email : this.state.data[0].email,
      title: this.state.title ? this.state.title : this.state.data[0].title,
      longTitle: this.state.longTitle ? this.state.longTitle : this.state.data[0].longTitle,
      introTitle: this.state.introTitle ? this.state.introTitle : this.state.data[0].introTitle,
      introLongTitle: this.state.introLongTitle ? this.state.introLongTitle : this.state.data[0].introLongTitle,
      videoLink: this.state.videoLink ? this.state.videoLink : this.state.data[0].videoLink,
      introText: this.state.introText ? this.state.introText : this.state.data[0].introText
    };

    //console.log(this.state.phone);

    axios.post('http://localhost:5555/data', { data })
      .then(res => {
        console.log(data);
        console.log(this.state.data[0]);
      })
  }
  render() {
    if (this.state.loading) {
      return (
        <div>
          <p> Loading... </p>
        </div>
      )
    }
    if (this.state.error || !this.state.data[0]) { // if request failed or data is empty don't try to access it either
      return (
        <div>
          <p> An error occured </p>
        </div>
      )
    }
    return (
      <form action="" onSubmit={this.handleSubmit}>
        <h2 className="center" >Изменить данные</h2>
        <div className="center"><img src={require('../img/orn.png')} alt="" className="orn" /></div>
        <h5>Phone:</h5>
        <input type="text" name="phone" defaultValue={this.state.data[0].phone} onChange={e => this.onChange(e)} />
        <h5>Email:</h5>
        <input type="text" name="email" defaultValue={this.state.data[0].email} onChange={e => this.onChange(e)} />
        <h5>Title:</h5>
        <input type="text" name="title" defaultValue={this.state.data[0].title} onChange={e => this.onChange(e)} />
        <h5>Description:</h5>
        <input type="text" name="longTitle" defaultValue={this.state.data[0].longTitle} onChange={e => this.onChange(e)} />
        <h2 className="center" >Intro:</h2>
        <div className="center"><img src={require('../img/orn.png')} alt="" className="orn" /></div>
        <h5>Title:</h5>
        <input type="text" name="introTitle" defaultValue={this.state.data[0].introTitle} onChange={e => this.onChange(e)} />
        <h5>Description:</h5>
        <input type="text" name="introLongTitle" defaultValue={this.state.data[0].introLongTitle} onChange={e => this.onChange(e)} />
        <h5>Link to video:</h5>
        <input type="text" name="videoLink" defaultValue={this.state.data[0].videoLink} onChange={e => this.onChange(e)} />
        <h5>Text:</h5>
        <textarea name="introText" id="" cols="30" rows="10" defaultValue={this.state.data[0].introText} onChange={e => this.onChange(e)}></textarea>
        <button type="submit" className="btn-large waves-effect waves-light xbutton">Save</button>
      </form>
    );
  }
}

export default Misc;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM