3

I am new to javascript and reactJS and I'm stuck. I have a javascript file where I make a REST call. The file looks like this:

var data;
function getDataRequest() {
 const request = new XMLHttpRequest();
    request.open('GET', "localhost:8080/getData", true);
    request.onload = function () {
        var data = JSON.parse(this.response);
        if (request.status >= 200 && request.status < 400) {
            products = data;
        } else {
            console.log('error');
        }
    };
    request.send();
}
var getDataList = function() {
    getDataRequest();
    return data;
};
getDataList();

And the file which contains the React component looks like this:

var = data;
class Datas extends React.Component {

    render() {
        data = this.getDataList;
        return (
            <DataTable data={data} />
        );
    }
}
export default Products;

The problem is that data in the React component remains 'undefined'. I am making the rest call in a different file because I want to call the rest call from multiple react components.

Catalin
  • 69
  • 1
  • 1
  • 10
  • You need to create a state, and write a method to update the state. Then export function from different fine and import it in the component.. and pass the state mutation method as a callback to the imported function and call it from there.. this is how you can connect all the async functions. – Arup Rakshit Sep 05 '18 at 07:24
  • You have a class Datas, then export default Products. Is this not all the file? – rrd Sep 05 '18 at 07:26
  • There is no `this.getDataList`. And what does `products = data;` do? What is `products`? It's not defined or used anywhere else. –  Sep 05 '18 at 07:27
  • Should be a list of objects wit id, description and name like: { "id": 1, "name": "Object0", "description": "desc1" }, { "id": 2, "name": "Object1", "description": "desc2" }, { "id": 3, "name": "Object2", "description": "desc2" } – Catalin Sep 05 '18 at 07:28
  • Possible duplicate of [how to return response of async call](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Mayank Shukla Sep 05 '18 at 07:28
  • The problem that in Datas I can't get the value that getDataList should return. the call works and data from the file with the request has the expected value – Catalin Sep 05 '18 at 07:33

4 Answers4

4

You're grabbing data from the server in your render call, which is a really bad idea. Use componentDidMount to load data, then store it in the state.

First, here's you Data.js:

export default {
  getDataList: () => fetch("//localhost:8080/getData").then(res => res.json())
};

In your Component, import Data from './Data';, then do this:

componentDidMount = () => {  // using this syntax auto-binds 'this'
  Data.getDataList().then(res => {
    this.setState({ data: res });
  });
}

render() {
  return (
    <DataTable data={this.state.data} />
  );
}
1

You need to be aware of the React component lifecycle. In a nutshell, there are certain functions that React calls in a certain order. Some are called before the component is rendered and some are called after. In your case, you want to make an API call once the component is rendered. An appropriate lifecycle method for this is componentDidMount. Please see here for more detailed information about the component lifecycle methods.

Below is an example of this behaviour. Note that I have used the fetch API instead of XmlHttpRequest. It is much cleaner to work with and is part of JavaScript.

class Example extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      loaded: false,
      something: ""
    };
  }

  componentDidMount() {
    fetch("exampleurl")
      .then(response => {
        return response.json();
      })
      .then(json => {
        // perform desired checks etc

        this.setState({
          something: json.someProperty
        });
      });
  }

  render() {
    if (!this.state.loaded) {
      return <div>{"Loading..."}</div>;
    }

    return <div>{this.state.something}</div>;
  }
}

export default Example;
tiget
  • 41
  • 1
  • 3
  • 1
    I agree with your answer, and it works, but I have to make this and more rest calls multiple times and I think that in the long run it is easier to have the calls written only once and get the data from another file. – Catalin Sep 05 '18 at 07:52
1

Firstly, there are no function getDataList in your React Component Datas. Secondly, if you want to call getDataList from your React Componet, please export or make your function is global. You can use:

window.getDataList = function() {
    getDataRequest();
    return data;
};

and in your React Component, you can call window.getDataList() easily.

Dai Nguyen
  • 69
  • 6
0

You need to pass a callback to your generic function to be able to update the state

function getDataRequest(callback) { // here
    const request = new XMLHttpRequest();
    request.open('GET', "localhost:8080/getData", true);
    request.onload = function () {
        var data = JSON.parse(this.response);
        if (request.status >= 200 && request.status < 400) {
            callback(data) // here
        } else {
            console.log('error');
        }
    };
    request.send();
}

You need to create a state and trigger the call in the componentDidMount, after the first render.

export default class Datas extends React.Component {

    state = {
        data: null // or [] ?
    }

    componentDidMount(){
        const callback = (value) => {
            this.setState({
                data: value
            })
        }
        this.getDataList(callback);
    }

    render() {
        const {
            data
        } = this.state;

        return (
            <DataTable data={data} />
        );
    }
}
ChrisR
  • 3,922
  • 1
  • 14
  • 24