1

I am trying to learn ReactJS with ES6 along with setting up an instance of Fixed-Data-Table. I'm using the ObjectDataExample example from the github repo, but instead of the faker() values fed to the DataListStore, I want to use a DataListStore that gets its cache from a remote JSON resource. This is how I have defined my DataListStore:

class MyDataListStore {

constructor(/* url string */ url) {
    this.url = url || 'http://localhost:8080/default-json';
    this._cache = [];
    this.pageSize = 1;
    this.size = 0;
    this.getRemoteData(url);
}

getRemoteData() {
    /**
     * Fetch remote JSON to be used in the store.
     */
    var that = this;
        fetch(this.url).then(function(response) {
          return response.json();
        }).then(function(j) {
          console.log(j);
          //this.pageSize = j["pages"];
          that.size = j["total"];
          that._cache = j["table"];
    if (that._cache) {
       // do something here?
    }
        });
}

getObjectAt(/*number*/ index) /*?object*/ {
    if (index < 0 || index > this.size){
        return undefined;
    }
    if (this._cache[index] === undefined) {
        //this._cache[index] = this.createFakeRowObjectData(index);
    }
    return this._cache[index];
}

getSize() {
    return this.size;
}


}

module.exports = MyDataListStore;

As you can see I'm following the FakeObjectDataListStore provided with the example from fixed-data-table more or less. The JSON is fetched properly, the _cache is populated with an array of objects, and when you output getSize once getRemoteData has executed, you do get the size of the _cache. However, I haven't figured out how my fixed-data-table Table component should be updated once the data has been fetched. Currently the Table is rendered but is simple blank with no rows.

class ObjectDataExample extends React.Component {
constructor(props) {
    super(props);
    this.state = {
    dataList: new MyDataListStore()
    };
}
render() {
    var {dataList} = this.state;
        return <Table
        rowHeight={70} rowsCount={dataList.getSize()} width={1170} height={500} headerHeight={30}>
    <Column
        header={<Cell>ID</Cell>}
    cell={<TextCell data={dataList} col="id" />}
        width={50}
    fixed={true}
    />
    <Column
        header={<Cell>Email</Cell>}
    cell={<TextCell data={dataList} col="email" />}
        width={300}
    fixed={true}
    />
    </Table>
}
}

module.exports = ObjectDataExample;

I think the main issue is that I don't have any code meant to populate the table once MyDataListStore is populated with the data from the async call. However, I can't find any help from the examples given in the Fixed-Data-Table github repo or the docs. Any idea how to get this done? I assume I need to set up some sort of event listener, but I'm not sure where/how to do this, as I'm still new to both ReactJS and Fixed-Data-Table.

Edit: I should also add that when the page loads, I get the following error: Uncaught TypeError: Cannot read property 'id' of undefined once I set the initial this.size to more than 0. So of course the table doesn't have the available data when it's first loading.

Edit 2: After looking into this further, it looks like if I run the fetch in componentDidMount of my ObjectDataExample and use this.setState(); to reset the dataList object, then I get the table updated. However, this looks a little messy and I'd assume there's a better way to do this directly from my MyDataListStore object.

Thanks,

Loic Duros
  • 5,472
  • 10
  • 43
  • 56

1 Answers1

1

One design issue with the current implementation of MyDataListStore is that it does not provide a way to notify the caller when the data has been loaded.

One possible way you might do this is to implement some sort of factory function (in the example below, I'm pretending that one exists called MyDataListStore.of) that returns a Promise that eventually resolves the MyDataListStore instance once the data loads:

// In the ObjectData component constructor, we call the MyDataListStore
// factory function and once it resolves, we assign it to our
// state. This will cause our component to re-render.
constructor() {
   MyDataListStore.of(myDataListStoreUrl).then(store => {
       this.setState({ dataList: store });
   });
}

Now, once the data in the data list store resolves, our template (specified in your render function) will render correctly.

The DataListStore.of function we used earlier might look something like this:

class MyDataListStore {
    static of(url) {
       const dataListStore = new MyDataListStore(url);
       return dataListStore.getRemoteData().then(() => return dataListStore);
    }
    /* ... other MyDataListStore properties/methods ... */
}

And finally we need to update the getRemoteData to return a promise. This is what will allow any clients of our MyDataListStore class to be notified that the data has loaded:

getRemoteData() {
    /**
     * Fetch remote JSON to be used in the store.
     */
    var that = this;

    // Return the chained promise! This promise will resolve
    // after our last callback is called. 
    return fetch(this.url).then(function(response) {
        return response.json();
    }).then(function(j) {
        console.log(j);
        //this.pageSize = j["pages"];
        that.size = j["total"];
        that._cache = j["table"];

        if (that._cache) {
            // do something here?
        }
    });
}
Calvin Belden
  • 3,114
  • 1
  • 19
  • 21