简体   繁体   中英

How to work with async functions?

Currently working on an app that makes axios requests from the client server to the back-end server.

Sometimes the application updates correctly and sometimes it lags behind/won't update until the next request. Any idea why?

Is there something wrong in my code? I'll try and add everything that is relevant.

The app is a Grocery List where the user can simply login through Google oauth. They then add/remove items from React State and a MongoDB database.

The state of the list is pulled from the database every time an item is added/removed.

App component

import React from 'react';
import ListForm from './ListForm';
import ListItem from './ListItem';
import * as helpers from '../helpers';

class App extends React.Component{
  state = {
    currentUser: {},
    items: []
  }

  componentDidMount() {
    helpers.fetchUser()
      .then(data => {
        this.setState({
          currentUser: data,
          items: data.shoppingList
        }, () => {
          console.log(this.state)
        });
      });
  }

  // Handle adding new items
onSubmit = (item) => {
  this.setState({items: this.state.items.concat([item])});
  helpers.addItem(item)
    .then(
      helpers.fetchUser()
        .then(data => {
          this.setState({
            currentUser: data,
            items: data.shoppingList
          }, () => {
            console.log(this.state);
          });
        })
      )
  }

  // Handle deletion of items
  onDelete = (deleteItem) => {
    helpers.removeItem(deleteItem)
      .then(
        helpers.fetchUser()
          .then(data => {
            this.setState({
              currentUser: data,
              items: data.shoppingList
            }, () => {
              console.log(this.state);
            })
          })
      )
  }

  renderContent = () => {
    const shoppingList = this.state.currentUser.shoppingList;
    const currentUser = this.state.currentUser;

    if(!currentUser.googleId) {
       return (
         <div className="row justify-content-center">
           <div>
             <a href="/auth/google" className="btn btn-primary"><i className="fa fa-google" />  Sign in with Google</a>
           </div>
         </div>
       );
    } else if(shoppingList === undefined || shoppingList.length < 1) {
        return (
          <div className="row justify-content-center">
            <h5>Add your first item!</h5>
          </div>
        );
    } else {
        return (
          <div>
            {this.state.items.map((item, index) =>
              <ListItem
                {...item}
                key={index}
                id={index}
                currentUser={this.state.currentUser}
                onDelete={this.onDelete}
              />
            )}
          </div>
        );
    }
  }

  render() {
    return (
      <div className="container row offset-4">
        <div className="jumbotron col-sm-6">
          <ListForm
            currentUser={this.state.currentUser}
            items={this.state.items}
            onSubmit={this.onSubmit}
          />
          {this.renderContent()}
        </div>
      </div>
    );
  }
};

export default App;

List Component

import React from 'react';

class ListForm extends React.Component {
  state = {
    value: ''
  }

  // Handle the submission of a new item to database and state.
  handleSubmit = e => {
    e.preventDefault();

    this.props.onSubmit({name: this.state.value});
    this.setState(prevState => ({value: ''}));
  }

  // Handle any changes within the input.
  onChange = e => {
    this.setState({value: e.target.value});
  }

  render() {
    return (
      <div className="col-xs-9">
          <h3>Grocery List</h3>
        <form className="form-control" onSubmit={this.handleSubmit}>
          <input style={{display: "inline", width: "60%", height: "2em"}} className="form-control" type="text"
            value={this.state.value}
            onChange={this.onChange}
            required
            />
          <button className="btn btn-success btn-sm float-right">Add item</button>
        </form>
        <div style={{marginTop: "10%"}}>
        </div>
      </div>
    );
  }
}

export default ListForm;

Helpers.js (Where requests are made)

import axios from 'axios';

export const fetchUser = async () => {
  const resp = await axios.get('/api/current_user');

  return resp.data;
}

export const addItem = async (newItem) => {
  const resp = await axios.post("/api/addItem", newItem);

  return resp.data;
}

export const removeItem = async (deleteItem) => {
  axios.delete("/api/removeItem", {data: {item: deleteItem}});
}

Routes involving user data

const mongoose = require('mongoose');
const User = require('../models/userSchema');

module.exports = (app) => {
  app.post('/api/addItem', async (req, res) => {
    const item = await req.body;

    req.user.shoppingList.push(item);
    req.user.save();

    console.log(req.user);

    res.send(item);
  });

  app.delete('/api/removeItem', (req, res) => {
    const itemName =  req.body.item;
    console.log(itemName);
    const index = req.user.shoppingList.findIndex(i => i.name === itemName);
    console.log(index);

    req.user.shoppingList.splice(index, 1);
    req.user.save();

    console.log(req.user);

    res.send(itemName);
  });
};

Please let me know if I need to add anything in order to make this more clear!

It's tough to say when looking at the code because there are no .catch clauses following your .then() 's. That would be the first place to check: what if your request sometimes fails? Also React devtools extension is great for inspecting state at runtime- if it's not a promise problem, you can certainly pin it down with that.

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