ReactJS fetchAPI JSON type - TypeError: content.forEach is not a function

262 Views Asked by At

I am using https://www.npmjs.com/package/react-metismenu for metismenu and using fetch api to get response from service. I get the response properly but getting below exception

Warning: Failed prop type: Invalid prop `content` of type `object` supplied to `MetisMenu`, expected an array
TypeError: content.forEach is not a function

The service code:

@GET
    @Path("/menu")
    @Produces(MediaType.APPLICATION_JSON)
    public String getMenuItems(@QueryParam("industry") String industry) {
        JSONArray response = new JSONArray();
        try{
            org.json.JSONObject obj = new org.json.JSONObject();
            obj.put("icon", "spinner");
            obj.put("label", "User Maintenance");
            obj.put("to", "#a-link");
            response.put(obj);

            org.json.JSONArray content = new org.json.JSONArray();
            obj = new org.json.JSONObject();
            obj.put("icon", "apple");
            obj.put("label", "System Controls");
            obj.put("to", "#b1-link");
            content.put(obj);
            obj = new org.json.JSONObject();
            obj.put("icon", "user");
            obj.put("label", "User Maintenance");
            obj.put("to", "#b2-link");
            content.put(obj);

            obj = new org.json.JSONObject();
            obj.put("icon", "gear");
            obj.put("label", "System Preferences");
            obj.put("content", content);            
            response.put(obj);

            obj = new org.json.JSONObject();
            obj.put("icon", "gear");
            obj.put("label", "Configuration");
            obj.put("to", "#c-link");
            response.put(obj);
        }
        catch(Exception e){

        }
        return response.toString();
    }

and the index.js code:

var content=fetch('http://localhost:8084/Accounting/rest/v1/company/menu?request=abc').then(function(response){
         return response
});
ReactDOM.render(
  <MetisMenu content={content} activeLinkFromLocation />,
  document.getElementById('root')
);

If I hardcode the const value then it works fine.

Got it working, the issue was CORS so I avoided CORS in my other application's web.xml whose service I am using. And changed the code with below part:

export default class MenuComponent extends Component {
  constructor() {
    super();
    this.state = {}
  }

componentDidMount(){
  fetch('http://localhost:8084/Accounting/rest/v1/company/menu?request=abc')
  .then(response => response.json())
  .then(parsedJSON => parsedJSON.data.map(menu => (
    {
      to: `${menu.to}`,
      icon: `${menu.icon}`,
      label: `${menu.label}`
      // content: `${menu.content}`
    }
  )))
  .then(content => this.setState({
    content
  }))
}

  render() {
    console.log('333');
    console.log(this.state.content);
    return (
      <MetisMenu content={this.state.content} activeLinkFromLocation />
    )
  }
}

The only issue now is that nested content within content is not working, can anyone please help me. I also tried the ajax mentioned in https://github.com/alpertuna/react-metismenu, and it also didnt work.

1

There are 1 best solutions below

13
Pavlo Kozlov On

Since fetch returns a promise, you need to wait while it's resolved using Promise.then or await approach.

var content = await fetch('http://localhost:8084/Accounting/rest/v1/company/menu?request=abc');

I suggest you wrap this fetching code in a separate component and pass the response to the setState method.

SomeComponent.js:

import React, { Component } from 'react'

export default SomeComponent extends Component {
  constructor() {
    this.state = {
      content: []
    }
  }
  
  componentDidMount() {
    fetch('http://localhost:8084/Accounting/rest/v1/company/menu?request=abc')
    .then((response) => this.setState({ content: response }));
  }
  
  render() {
    return (
      <MetisMenu content={this.state.content} activeLinkFromLocation />
    )
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

index.js:

import SomeComponent from './SomeComponent';
    
ReactDOM.render(
  <SomeComponent />,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>