2

-Can someone please help me with this. I am getting an error described in the title of this question. I want to put JSON data inside react-grid-layout component. This library can be found on (https://github.com/STRML/react-grid-layout)

import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import Employee from './Employee'; 
import "./react-grid-layout/css/styles.css";
import "./react-resizable/css/styles.css"


var ReactGridLayout = require('react-grid-layout');

var data = [];

class MyFirstGrid extends React.Component {
    constructor() {
        super();
        this.state = {
            data: []
        };
    }

    componentDidMount(){
        fetch("http://localhost:8080/TrainingWebMvcSpring2/roottypes/listAll.do")
            .then( (response) => {
                return response.json() })
                    .then( (json) => {
                        this.setState({data: json});
                    });
    }


    render () {
        console.log(data);

        return (
            <ReactGridLayout className="layout" cols={12} rowHeight={30} width={1200}>
                {this.state.data.map(function(item, key){
                    return(
                        <div>
                        <div key="a" data-grid={{x: 0, y: 0, w: 1, h: 2, static: true}}> {item}</div>
                        <div key="b" data-grid={{x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4}}> {item} </div>
                        <div key="c" data-grid={{x: 4, y: 0, w: 1, h: 2}}> {item} </div>
                        </div>
                    )
                })}
            </ReactGridLayout>
        )
    }
}

export default MyFirstGrid;
DSM
  • 342,061
  • 65
  • 592
  • 494
  • When u getting error during initial load or after fetch API? – RIYAJ KHAN Feb 21 '18 at 08:12
  • Can you please show the structure of JSON? – Amanshu Kataria Feb 21 '18 at 08:23
  • Please do not vandalize your posts. Once you've posted a question, it belongs to the Stack Overflow community at large (under the CC-by-SA license). If you would like to disassociate this post from your account, see [What is the proper route for a disassociation request?](https://meta.stackoverflow.com/questions/323395/what-is-the-proper-route-for-a-dissociation-request) – DSM Feb 21 '18 at 18:23

4 Answers4

2

ReactJS: TypeError: this.state.data.map is not a function?

Array#map is available on array.

After fetch API call ,

this.setState({data: json});

json returning as an object and not an array which converting data to an object

Change this to :

this.setState({data: [...json]});
RIYAJ KHAN
  • 15,032
  • 5
  • 31
  • 53
1

Since your JSON structure is as follows:

{
    array: [{},{},{}]
}

So, setting state this way will solve your issue: this.setState({data: json.array});.

Amanshu Kataria
  • 2,838
  • 7
  • 23
  • 38
  • Seems like an issue in the JSON. It's currently `{ array: [ { code: "CORPORATE", description: "Corporate" }] }` , where as it should be like `{ "array": [ { "code": "CORPORATE", "description": "Corporate" }] }`. – Amanshu Kataria Feb 21 '18 at 09:50
  • I never came across such a JSON thing. – Amanshu Kataria Feb 21 '18 at 10:02
  • Try sending a hardcoded JSON of the type `{"array":[{},{}]}` from backend, if that works then it means the problem is with the backend code. – Amanshu Kataria Feb 21 '18 at 10:55
  • You're getting this error because `data.array` is not an array and you're using map function over it. So again, check your JSON. – Amanshu Kataria Feb 21 '18 at 13:20
0

You should be checking that the fetch call was successful. It's not enough to add a .catch() at the end of the promise chain (which you should anyway), you must also check that the successful call returned an OK response instead of, for example, a 404. Like this, for example:

class MyFirstGrid extends React.Component {
    constructor() {
        this.state = {
            data: []
        }
    }

    componentDidMount(){
        fetch('http://localhost:8080/JiwayTrainingWebMvcSpring2/roottypes/listAll.do')
            .then( (response) => {
                if (response.ok) {
                    return response.json()
                } else {
                    throw new Error(`Fetch failed with code ${response.code}`)
                }
            })
            .then(json => {
                this.setState({data: json})
            })
            .catch(err => { console.log(`Something failed: ${err.message}`) };
    }

    render () {
        console.log(this.state.data);
        return (
            <ReactGridLayout className="layout" cols={12} rowHeight={30} width={1200}>
                {this.state.data.map(function(item, key){
                    return(
                        <div>
                        <div key="a" data-grid={{x: 0, y: 0, w: 1, h: 2, static: true}}> {item}</div>
                        <div key="b" data-grid={{x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4}}> {item} </div>
                        <div key="c" data-grid={{x: 4, y: 0, w: 1, h: 2}}> {item} </div>
                        </div>
                    )
                })}
            </ReactGridLayout>
        )
    }
}

export default MyFirstGrid
Miguel Calderón
  • 3,001
  • 1
  • 16
  • 18
  • How can you access state without using this.state in render method? – Amanshu Kataria Feb 21 '18 at 08:22
  • I don't know why would you want to do that, but you can assign the fetched data to any other variable like `this.data` and then retrieve that in the `render()` function. Only that, if you don't change the state, the `render()` function won't be called. – Miguel Calderón Feb 21 '18 at 08:26
  • 1
    But you're not doing so. You're setting state instead and consoling `data` which doesn't even exist. – Amanshu Kataria Feb 21 '18 at 09:24
  • Now I have successfully fetched but I am getting undefined object... do you have any idea where is the problem? And the grid is empty of course... –  Feb 21 '18 at 09:35
  • Check with the updated code (I just changed the variable logged in the console) and see what's in there, please. – Miguel Calderón Feb 21 '18 at 09:53
  • So, I have fixed my code and now I get proper JSON object after fetch (http://jsbin.com/?html,output) but I get this error now TypeError: this.state.data.map is not a function (which is a brand new error), my current code is: http://jsbin.com/lehicalupo/edit?html,output . –  Feb 21 '18 at 13:30
  • Could you please copy and paste here the data you get from the server? (from devtools). – Miguel Calderón Feb 21 '18 at 13:41
0

var data = [] is a global empty array. I don't see you assign it to anything else, so it will always be a empty array. So console.log(data) is []. Just don't use it.

response.json() is same as JSON.parse(response.text()), which returns a object, or an object array. In your case, since there is no map function, I guess it returns an object.

The easiest way to transform an object to an array is to use Object.keys() function.

const keys = Object.keys(json); // eg: json = {a: 1, b: 2}
const data = keys.map(key => json[key]); // eg: data = [1, 2]
this.setState({ data: data });

Since you haven't tell us the structure of your json response, it is hard to provide a specific answer to your problem.

This is how to test if response is array of object:

if (json.length) { /* array */ } 
eles { /* object will return undefined, which is false */ }

Note: Just saw your comment. this.setState({ data: json.array }) should do.

  • Another problem in your code is constructor(props) { super(props); } The props is missing in your class constructor

This should get you started, don't forget the key, when using map function

class MyFirstGrid extends React.Component {
  state = { data: [] };

  async componentDidMount() {
    try {
      const response = await fetch("http://localhost:8080/TrainingWebMvcSpring2/roottypes/listAll.do");
      const data = response.json().array;
      console.log(data, data.length);
      this.setState({
        data: data,
      });
    } catch (err) {
      console.error(err);
    } 
  }

  render() {
    const dataGrid = this.state.data.map((item, index) => (
      <div key={index}>
        <div key="a" data-grid={{x: 0, y: 0, w: 1, h: 2, static: true}}> {item}</div>
        <div key="b" data-grid={{x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4}}> {item} </div>
        <div key="c" data-grid={{x: 4, y: 0, w: 1, h: 2}}> {item} </div>
      </div>
    ));

    return(
      <ReactGridLayout className="layout" cols={12} rowHeight={30} width={1200}>
        {dataGrid}
      </ReactGridLayout>
    );
  }
}
FisNaN
  • 2,517
  • 2
  • 24
  • 39
  • try `console.log(json.array)` first. BTW add `props` to your constructor, and `catch` after `fetch`. – FisNaN Feb 21 '18 at 09:03
  • `constructor(props) { super(props); this.state = { data: [] }; }` is the data initialization. Or `state = { data: [] };` in `MyFirstGrid` class for short. They are same thing. – FisNaN Feb 21 '18 at 09:18
  • Updated my answer. Try `console.log` your json response before `setState` first. – FisNaN Feb 21 '18 at 09:37
  • BTW every time use `map` function, always provide a `key`, and index is a very bad key. It leads to unpredictable behavior when `splice` the array – FisNaN Feb 21 '18 at 09:40
  • So `response.json().array` is not an array. What does it look like? – FisNaN Feb 21 '18 at 09:46
  • `response.json()` should provide a object rather than a json string. Have you set header `Content-Type` to `application/json` from your sever? – FisNaN Feb 21 '18 at 09:58
  • 1
    I don't know how jsp works. But I would recommend you test with Postman first. If it can't GET json response, then React can't neither. If you are only interested to get drag and drop grid going, try setup a global variable holds your json string, then use `JSON.parse(data)` to test the render function. – FisNaN Feb 21 '18 at 10:21