0

I'm able to loop through JSON data to create an array filled with numbers, but when I go to create the list items it doesn't work. The component just renders an empty list.

When I console.log(ticketNumbers) right before the map function, it shows as a collapsed Array [] until I expand it (it then shows all the values)

function apiCall() {
  var ticketNumbers = [];
  var memId = 'xxx'; 
  var myInit = { 
      method: 'GET',
      mode: 'cors',
      headers: {
        'authorization': "xxx",
    'Access-Control-Allow-Origin':'*',
    'content-type': "application/json",
    'cache-control': "no-cache"
          },
      params: {
    'orderBy': 'status/name asc',
    'pageSize': 300,
    'conditions': "resources contains '" + memId + "' AND status/id not in (17,165,36,163,164,42,73,46,78,148,34,132,45,159,60,168,106,51,72,95)"
          }
  };
  axios.get('Url', myInit)
    .then((response) => {
      console.log(response.data)
      for (var ticket in response.data) {
        ticketNumbers.push(response.data[ticket].id)
      };  
     })
    return ticketNumbers
}
class TicketContainer extends Component {
  constructor(props) {
    super(props)
    this.state = {
      data: [],
      loading: true,
    };
  }
  componentWillMount() {
      this.setState({
        data: {
      numbers: apiCall()
        },      
      loading: false
        })
      };
  render() {
    return(
      <div>
    {this.state.loading ? 'Loading' : <Tickets data={this.state.data} />}
      </div>
    )
  }
}

class Tickets extends Component {
  render() {
    const stuff = this.props;
    var ticketList = stuff.data.numbers;
    console.log(ticketList);
    return(
      <div>
        <ul>Ticket Number
          {ticketList.map((ticket, index) => {
            return <li key={index}>sweet</li>;
          })}   
        </ul>
      </div>
    );
  }
}

2 Answers2

0

You should correctly use Promise to solve this. First, let's change apiCall so that it will return a Promise:

function apiCall() {
  var ticketNumbers = [];
  var memId = 'xxx'; 
  var myInit = { 
      method: 'GET',
      mode: 'cors',
      headers: {
        'authorization': "xxx",
    'Access-Control-Allow-Origin':'*',
    'content-type': "application/json",
    'cache-control': "no-cache"
          },
      params: {
    'orderBy': 'status/name asc',
    'pageSize': 300,
    'conditions': "resources contains '" + memId + "' AND status/id not in (17,165,36,163,164,42,73,46,78,148,34,132,45,159,60,168,106,51,72,95)"
          }
  };
  return axios.get('Url', myInit)
    .then((response) => {
      console.log(response.data)
      for (var ticket in response.data) {
        ticketNumbers.push(response.data[ticket].id)
      }
      return ticketNumbers;
     });
}

You know have a Promise based api that can be used like this:

apiCall().then(ticketNumbers => console.log(ticketNumbers);

We just need to modify componentWillMount know:

componentWillMount() {
     apiCall().then(numbers => this.setState({ loading: false, data: numbers });
}
Axnyff
  • 9,213
  • 4
  • 33
  • 37
  • it's a suggestion let him know about the success and failure in promise. It'll be beneficial for him – Hassaan Jan 10 '18 at 06:07
0

The apiCall function calls an API which is asynchronous process and returning ticketNumbers from function request won't return the result as the return statement will be executed before the API response is ready and ticketNumbers array is populated.

The easiest way for you to do this is to define this function in the React class and directly setState in the callback of axios request

class TicketContainer extends Component {
  constructor(props) {
    super(props)
    this.state = {
      data: [],
      loading: true,
    };
  }
  componentWillMount() {
      this.apiCall()

  };


  apiCall =() => {

      var memId = 'xxx'; 
      var myInit = { 
          method: 'GET',
          mode: 'cors',
          headers: {
            'authorization': "xxx",
            'Access-Control-Allow-Origin':'*',
            'content-type': "application/json",
            'cache-control': "no-cache"
          },
          params: {
            'orderBy': 'status/name asc',
            'pageSize': 300,
            'conditions': "resources contains '" + memId + "' AND status/id not in (17,165,36,163,164,42,73,46,78,148,34,132,45,159,60,168,106,51,72,95)"
              }
      };
      axios.get('Url', myInit)
        .then((response) => {
          var ticketNumbers = [];
          for (var ticket in response.data) {
            ticketNumbers.push(response.data[ticket].id)
          }; 
          this.setState({data: ticketNumbers, loading: false}) 
         })
  }
  render() {
    return(
      <div>
    {this.state.loading ? 'Loading' : <Tickets data={this.state.data} />}
      </div>
    )
  }
}

class Tickets extends Component {
  render() {
    const stuff = this.props;
    var ticketList = stuff.data.numbers;
    console.log(ticketList);
    return(
      <div>
        <ul>Ticket Number
          {ticketList.map((ticket, index) => {
            return <li key={index}>sweet</li>;
          })}   
        </ul>
      </div>
    );
  }
}

In case you are wondering why the console.log() statment logs the array, check this answer Value below was evaluated just now in JavaScript object

Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400