Как работать с асинхронными функциями?

1

В настоящее время работает над приложением, которое делает запросы axios с клиентского сервера на внутренний сервер.

Иногда приложение обновляется правильно, а иногда оно отстает/не будет обновляться до следующего запроса. Любая идея почему?

Что-то не так в моем коде? Я постараюсь добавить все, что уместно.

Приложение представляет собой список продуктов, в котором пользователь может просто войти в систему через Google oauth. Затем они добавляют/удаляют элементы из состояния React и базы данных MongoDB.

Состояние списка извлекается из базы данных каждый раз, когда элемент добавляется/удаляется.

Компонент приложения

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;

Список компонентов

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 (где делаются запросы)

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}});
}

Маршруты с использованием пользовательских данных

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);
  });
};

Пожалуйста, дайте мне знать, если мне нужно что-то добавить, чтобы сделать это более ясным!

  • 0
    Было бы лучше, если бы вы централизовали свое состояние с помощью Redux, чтобы вам было легко управлять им
  • 1
    Спасибо, цель состояла в том, чтобы просто использовать React!
Теги:
axios

1 ответ

0
Лучший ответ

Трудно сказать, когда смотришь на код, потому что нет .catch предложений .catch следующих за вашим .then(). Это будет первое место, чтобы проверить: что, если ваш запрос иногда терпит неудачу? Кроме того, расширение React devtools отлично подходит для проверки состояния на runtime-, если это не проблема обещания, вы можете, конечно, с этим справиться.

  • 0
    Спасибо за это. Я думаю, что это может быть связано с тем, что я выполняю два запроса по сути. (helpers.addItem, а затем helpers.fetchUser). Я мог бы просто запустить helpers.addItem и обновить состояние в .then () с возвращенными и обновленными данными.
  • 0
    еще одна вещь! без слишком большого контекста трудно сказать, является ли это допустимой ошибкой. но когда компонент монтируется, вы выбираете пользовательские данные и устанавливаете их в состояние. при добавлении элементов вы вызываете выборку пользовательских данных снова. Является ли выборка пользовательских данных fn, который возвращает обещание, которое просматривает состояние для пользовательских данных и, если да, разрешает, или это просто повторная загрузка? если последнее, что может быть источником, в противном случае, вероятно, не стоит беспокоиться
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню