85

I have a React component and I want to load in my JSON data from a file. The console log currently doesn't work, even though I'm creating the variable data as a global

'use strict';

var React = require('react/addons');

// load in JSON data from file
var data;

var oReq = new XMLHttpRequest();
oReq.onload = reqListener;
oReq.open("get", "data.json", true);
oReq.send();

function reqListener(e) {
    data = JSON.parse(this.responseText);
}
console.log(data);

var List = React.createClass({
  getInitialState: function() {
    return {data: this.props.data};    
  },
  render: function() {
    var listItems = this.state.data.map(function(item) {
        var eachItem = item.works.work;        

        var photo = eachItem.map(function(url) {
            return (
                <td>{url.urls}</td> 
            )
        });
    });
    return <ul>{listItems}</ul>
  }
});

var redBubble = React.createClass({
    render: function() {
      return (
        <div>
          <List data={data}/>          
        </div>
      );
    }
  });

module.exports = redBubble;

Ideally, I would prefer to do it something like this, but it's not working - it tries to add ".js" onto the end of the filename.

var data = require('./data.json');

Any advice on the best way, preferably the "React" way, would be much appreciated!

Desmond
  • 1,386
  • 2
  • 19
  • 32
  • 2
    The `console.log` works just fine, you're just calling it before `reqListener` is ever called. – Jordan Running Aug 01 '15 at 05:11
  • Thanks for reply Jordan. In the code it's coming after reqListener, so I'm not sure if I understand. Could you elaborate please? – Desmond Aug 01 '15 at 05:39
  • 2
    Your Ajax request takes time. JavaScript doesn't wait for the request to finish before moving on to the next instruction (because the request could take minutes or even hours to complete). We call this "asynchronous" (or sometimes "non-blocking") execution. Immediately after `send()` is called, `console.log` is called... and some time later the Ajax request finishes and `reqListener` is called. If you want something to happen only after the Ajax request is completed, you have to make that thing happen in `reqListener`. – Jordan Running Aug 01 '15 at 05:47
  • possible duplicate of [What is the difference between synchronous and asynchronous programming (in node.js)](http://stackoverflow.com/questions/16336367/what-is-the-difference-between-synchronous-and-asynchronous-programming-in-node) – Jordan Running Aug 01 '15 at 05:47
  • Thanks Jordan, that does make sense now. Thanks for taking the time to explain and the other link helped. I tried to move all my React code inside the reqListener, so it would work in the callback, but that seems like a bad idea. Is there a way to wait for the response before running the rest of the code? Thanks again. – Desmond Aug 01 '15 at 07:22

8 Answers8

154

I was trying to do the same thing and this is what worked for me (ES6/ES2015):

import myData from './data.json';

I got the solution from this answer on a react-native thread asking the same thing: https://stackoverflow.com/a/37781882/176002

Community
  • 1
  • 1
rockfakie
  • 1,930
  • 3
  • 15
  • 9
  • 12
    If you're using this method with webpack, you need json-loader for the imported json files. – kevr Nov 12 '16 at 18:17
  • 3
    Thank you! I've been looking for a simple way to access json data in JSX, and this is exactly it! – Matt Brand Aug 04 '17 at 16:53
  • 6
    Note that this will compile your JSON into the bundle, making hot-swapping JSON files impossible. That's probably fine for a lot of use cases, but it wasn't for mine. – Wilson Biggs Nov 07 '18 at 18:37
  • this answer should be marked as the most accurate answer, but with `json-loader` package example – Syed Aqeel Mar 11 '19 at 07:45
  • Worked for me. I’m using rollup. Previously had `var data = import(‘./data.json’)` which imported a Promise. Changing this to `import data from ‘./data.json’` gave direct access to the imported object. – Max MacLeod Jan 14 '20 at 13:26
26

The simplest and most effective way to make a file available to your component is this:

var data = require('json!./data.json');

Note the json! before the path

César D. Velandia
  • 1,295
  • 10
  • 9
  • 3
    This will not work unless you add a library for that. As this is not supported by default in React. example library :- https://www.npmjs.com/package/json-loader – Gopinath Langote Jul 20 '17 at 10:40
  • 2
    `json-loader` is included with newer Webpack versions, I believe, but you may still need to add something to your Webpack config to use that exact syntax. Do some research into it. – agm1984 Sep 28 '17 at 21:33
  • @agm1984 things have changed since 2015, it would be nice if you provide a complete answer instead. – César D. Velandia Oct 29 '17 at 23:49
  • 2
    I believe the newest Webpack versions include json-loader so you do not need to install it or declare it in your config file. I would recommend trying to just `import FILE_AS_VARIABLE from './file/location.json'` – agm1984 Oct 30 '17 at 00:28
  • See answer here: https://stackoverflow.com/questions/43735486/load-static-json-file-in-webpack – agm1984 Oct 30 '17 at 00:30
  • Also see the answer in this question by `rockfakie` – agm1984 Oct 30 '17 at 00:31
  • with React v16.11.0 and a default project init, was able to simply add `var data = require('./data.json');` – Max MacLeod Nov 07 '19 at 15:08
19

You are opening an asynchronous connection, yet you have written your code as if it was synchronous. The reqListener callback function will not execute synchronously with your code (that is, before React.createClass), but only after your entire snippet has run, and the response has been received from your remote location.

Unless you are on a zero-latency quantum-entanglement connection, this is well after all your statements have run. For example, to log the received data, you would:

function reqListener(e) {
    data = JSON.parse(this.responseText);
    console.log(data);
}

I'm not seeing the use of data in the React component, so I can only suggest this theoretically: why not update your component in the callback?

John Weisz
  • 23,615
  • 9
  • 74
  • 118
  • Thanks very much for your help John. I've been looking into how to update the component on the callback but not having much luck. Is it to do with the state? I'm still a newbie to React! I've updated the code to show how the component is working - are you able to tell me how to pass the data in on callback? Thanks again! – Desmond Aug 02 '15 at 09:25
  • @Desmond Yes, state can work, as a component will be rerendered when its state changes. – John Weisz Aug 04 '15 at 09:46
  • 4
    `zero-latency quantum-entanglement connection` maybe it's time to invent those, just so that people don't have to learn about async anymore... – ssc Nov 13 '18 at 14:36
11
  1. Install json-loader:
npm i json-loader --save
  1. Create data folder in src:
mkdir data
  1. Put your file(s) there.

  2. Load your file:

var data = require('json!../data/yourfile.json');
nik7
  • 747
  • 2
  • 8
  • 17
ChaosPredictor
  • 2,885
  • 1
  • 24
  • 35
  • A had the "Critical dependency: the request of a dependency is an expression" error when NOT using `json!`. Thanks. – secavfr Nov 27 '19 at 18:14
  • 1
    is there anyway that I can use .json file from outside of the src folder? I am using create-react-app for my project – Chamod Pathirana Dec 26 '19 at 09:45
11

If you have couple of json files:

import data from 'sample.json';

If you were to dynamically load one of the many json file, you might have to use a fetch instead:

fetch(`${fileName}.json`)
  .then(response => response.json())
  .then(data => console.log(data))
jsbisht
  • 6,993
  • 6
  • 42
  • 51
2

My JSON file name: terrifcalculatordata.json

[
    {
      "id": 1,
      "name": "Vigo",
      "picture": "./static/images/vigo.png",
      "charges": "PKR 100 per excess km"
    },
    {
      "id": 2,
      "name": "Mercedes",
      "picture": "./static/images/Marcedes.jpg",
      "charges": "PKR 200 per excess km"
    },
    {
        "id": 3,
        "name": "Lexus",
        "picture": "./static/images/Lexus.jpg",
        "charges": "PKR 150 per excess km"
      }
]

First , import on top:

import calculatorData from "../static/data/terrifcalculatordata.json";

then after return:

  <div>
  {
    calculatorData.map((calculatedata, index) => {
        return (
            <div key={index}>
                <img
                    src={calculatedata.picture}
                    class="d-block"
                    height="170"
                />
                <p>
                    {calculatedata.charges}
                </p>
            </div>
                  
Nicolás Alarcón Rapela
  • 1,998
  • 1
  • 13
  • 27
Khadim Rana
  • 107
  • 4
1

You could add your JSON file as an external using webpack config. Then you can load up that json in any of your react modules.

Take a look at this answer

0

If you want to load the file, as part of your app functionality, then the best approach would be to include and reference to that file.

Another approach is to ask for the file, and load it during runtime. This can be done with the FileAPI. There is also another StackOverflow answer about using it: How to open a local disk file with Javascript?

I will include a slightly modified version for using it in React:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: null
    };
    this.handleFileSelect = this.handleFileSelect.bind(this);
  }

  displayData(content) {
    this.setState({data: content});
  }

  handleFileSelect(evt) {
    let files = evt.target.files;
    if (!files.length) {
      alert('No file select');
      return;
    }
    let file = files[0];
    let that = this;
    let reader = new FileReader();
    reader.onload = function(e) {
      that.displayData(e.target.result);
    };
    reader.readAsText(file);
  }

  render() {
    const data = this.state.data;
    return (
      <div>
        <input type="file" onChange={this.handleFileSelect}/>
        { data && <p> {data} </p> }
      </div>
    );
  }
}
bizi
  • 3,033
  • 1
  • 24
  • 26