0

I have two jsx files. TodoAPI.jsx has a function called getTodos() that uses axios to fetch data from a mongodb database and does so successfully as shown by testing. This function is usually called by certain lines in TodoApp.jsx, where apparently the entire code is executed before getTodos() even returns the array. Therefore, all the arrays that were supposed to be filled by getTodos() remain undefined. I made sure I am not wrong about this by using this setTimeout(function(){ console.log(TodoAPI.getTodos()); }, 3000); in TodoApp.jsx, where it actually printed the array.

How can I make sure getTodos() is finished before the rest of the code even starts? Or is there a better solution?

Here are the relevant parts of the code: TodoAPI.jsx:

var $ = require('jquery');
import axios from 'axios';

module.exports = {
  setTodos: function (todos) {
    if ($.isArray(todos)) {
      localStorage.setItem('todos', JSON.stringify(todos));
      return todos;
    }
  },
  getTodos: function () {
    let todos = [];
    axios({
      method: 'get',
      //url:'https://nameless-island-69625.herokuapp.com/todos',
      url: 'http://localhost:3000/todos',
      headers:{ 
        'x-auth': localStorage.getItem('x-auth') 
      }
    }).then(function(response) {
      todos = $.extend(true, [], response.data.todos);
      console.log('successful response from todos');
    }).then(() => {
      console.log(todos);
      return todos;
    }).catch((e) => {
      console.log('failed response from todos');
      console.log(e);
    });
    // return [{name:'asd'},{name:'qwe'},{name:'fgd'},];
  },

TodoApp.jsx:

var React = require('react');
var uuid = require('node-uuid');
var moment = require('moment');
const axios = require('axios');

var TodoList = require('TodoList');
var AddTodo = require('AddTodo');
var TodoSearch = require('TodoSearch');
var TodoAPI = require('TodoAPI');


var TodoApp = React.createClass({
  getInitialState: function () {
    return {
      showCompleted: false,
      searchText: '',
      todos: TodoAPI.getTodos()
    };
  },

rest of the code can be found here but I am sure that the problem is in the code above.

2
  • have you considered returning something in getTodos: function () { Commented Nov 4, 2017 at 0:58
  • Yeah I tried returning outside .then() but I get the same problem, only this time the empty array is returned instead of an undefined. The problem is that the function is done before the data arrives. Commented Nov 4, 2017 at 1:00

1 Answer 1

1

You can't assign the todos state in getInitialState because the api call is async. Instead, set todos in componentDidMount. Something like:

componentDidMount() {
  axios.get('http://localhost:3000/todos')
    .then(res => {
      this.setState({ todos: res.data.todos });
    });
}

If you'd like your api calls in a separate file, then be sure to return axios(... from your function and in componentDidMount do something like:

componentDidMount() {
  getTodos().then(todos => {
    this.setState({ todos });
  });
}

In that case your getTodos function might look like:

getTodos: function () {
  return axios({
    method: 'get',
    url: 'http://localhost:3000/todos',
    headers:{ 
      'x-auth': localStorage.getItem('x-auth') 
    }
  }).then(function(response) {
    return response.data.todos;
  })
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much. I altered my code using componentDidMount() to look like this: var TodoApp = React.createClass({ getInitialState: function () { return { showCompleted: false, searchText: '', todos: [] }; }, componentDidMount: function() { TodoAPI.getTodos().then(todos => { console.log(todos); this.setState({ todos }); }); },

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.