1

I am struggling a bit with some react fundamentals, mainly the flow of data and the jsx syntax, sorry about the noob question.

I have two json that I am making chained api calls to in Main.js, the data is then passed down to SensorList.js. In this component I have a function that renders a list of sensors, each Sensor.js has it key set to an id specified in the json and has its props set based on the data in the json.

Currently I am able to grab the first corresponding piece of data for each sensor and pass this down to the relevant child components. I need to pass down the whole array of the corresponding data to a child Graph.js component, currently my map function is grabbing only the first element in each array.

My question is how do I actually pass down the whole arrays of the value and time data of each sensor to it's child graph component?

Thanks in advance.

sensors.json

[
  {
    "id": "46c634d04cc2fb4a4ee0f1596c5330328130ff80",
    "name": "external"
  },
{
    "id": "d823cb4204c9715f5c811feaabeea45ce06736a0",
    "name": "office"
  },
{
    "id": "437b3687100bcb77959a5fb6d0351b41972b1173",
    "name": "common room"
  }
]

Sample of data.json

[
  {
    "sensorId": "437b3687100bcb77959a5fb6d0351b41972b1173",
    "time": 1472120033,
    "value": 25.3
  },
{
   "sensorId": "437b3687100bcb77959a5fb6d0351b41972b1173",
   "time": 1472119853,
   "value": 25.1
 },
{
  "sensorId": "437b3687100bcb77959a5fb6d0351b41972b1173",
  "time": 1472119673,
  "value": 25.1
},

SensorList.js

var SensorList = React.createClass({
  render: function() {
    var {data, sensors} = this.props;

    var renderSensors = () => {
      return sensors.map((sensor) => {
        return <Sensor key={sensor.id} name={sensor.name} value={data.get(sensor.id)}/>
        });
    };

    return (
      <div>
        {renderSensors()}
      </div>
    );
  }
});

Main.js

var Main = React.createClass({
  getInitialState: function() {
    return {
      sensors: [],
      sensorsData: []
    };
  },

  componentDidMount: function() {
    var _this = this;
    this.serverRequest =
      axios
        .get("http://localhost:3000/sensors.json")
        .then(function(result) {
          _this.setState({
            sensors: result.data
          });
        })
      axios
        .get("http://localhost:3000/data.json")
        .then(function(result) {
          var sensorDataToId = new Map();
          for(var i = 0; i < result.length; i++) {
            var datum = result[i];
            var sensorId = datum.sensorId;
            if (sensorDataToId.get(sensorId) === undefined) {
              sensorDataToId.set(sensorId, []);
            }

            sensorDataToId.get(sensorId).push(datum)
          }
          _this.setState({
            sensorsData: result.data
          });
        })
  },

  componentWillUnmount: function() {
    this.serverRequest.abort();
  },

  render: function() {
    var {sensors, sensorsData} = this.state;

    return (
      <div className="sensorList">
        <SensorList sensors={sensors} data={sensorsData}/>
      </div>
    );
  }
});
Luke Aveil
  • 19
  • 1
  • 5

2 Answers2

0

Start by reshaping your data. Take the data list and turn it into a map of sensor ids to arrays of data (this has nothing to do with react, and should probably be done wherever the AJAX response is initially handled); then in your sensors.map, just pass sensorDataToId.get(sensor.id)

The reshaping could look like:

var sensorDataToId = new Map();
for(var i = 0; i < data.length; i++) {
  var datum = data[i];
  var sensorId = datum.sensorId;
  if (sensorDataToId.get(sensorId) === undefined) {
    sensorDataToId.set(sensorId, []);
  }

  sensorDataToId.get(sensorId).push(datum)
}

Update your setState call to

_this.setState({sensorsData: sensorDataToId});

Then your sensors.map :

var renderSensors = () => {
  return sensors.map((sensor) => {
    return <Sensor key={sensor.id} name={sensor.name} value={data.get(sensor.id)}/>
  });
};
Alejandro C.
  • 3,771
  • 15
  • 18
  • Thanks for the response. I have updated my post above and included the component where I am making the api calls. Are you saying reshape the data within _this.setState in the second response? – Luke Aveil Nov 29 '16 at 15:22
  • @LukeAveil In that callback, but before setState. I'd call setState with the reshaped data. – Alejandro C. Nov 29 '16 at 15:23
  • I have updated the callback as per above, everything seems to all be working still. I am a bit unsure where you mean to put 'sensorDataToId.get(sensor.id)' in sensors.map? Do you mean now remove the dataList.map and if statement and replace it with 'sensorDataToId.get(sensor.id)'? Cheers. – Luke Aveil Nov 29 '16 at 15:45
  • @LukeAveil updated my answer with a few more details. Does that help? – Alejandro C. Nov 29 '16 at 16:42
  • Okay cool that helps. Although I am now getting the error `bundle.js:19889 Uncaught (in promise) ReferenceError: data is not defined` – Luke Aveil Nov 29 '16 at 16:58
  • There seems to be an issue with the map, when I try to access it in the react chrome dev tools I get the following error message `backend.js:7349 Uncaught TypeError: Method Map.prototype.size called on incompatible receiver #` – Luke Aveil Nov 29 '16 at 17:01
  • I have updated my question to show the code I am now running as per your advice... – Luke Aveil Nov 29 '16 at 17:05
  • @LukeAveil in main.js update your `setState` call to use the new `sensorDataToId`, and replace uses of `dataList` with `data` in both main.js and sensorlist.js. – Alejandro C. Nov 29 '16 at 17:19
  • I am getting the error `bundle.js:19889 Uncaught (in promise) TypeError: data.get is not a function`. It seems as though an empty map is being created and when I try to look at in react dev tools I still get the error `backend.js:7349 Uncaught TypeError: Method Map.prototype.size called on incompatible receiver #`. The empty map is getting passed down to sensorList. – Luke Aveil Nov 30 '16 at 11:48
  • In this case what is the benefit of having the data structured as a map? – Luke Aveil Nov 30 '16 at 15:02
0

How about you iterate through one list and use the 'find' method to find the properties in the other.

var renderSensors = () => {
  return(
  sensors.map((sensor) => {
      var dataItem = dataList.find((data)=>{
          return (data.sensorId === sensor.id)
      }) 
  return(
      <Sensor key={dataItem.sensorId} name={sensor.name} value={dataItem.value} time={dataItem.time}/>)      
    })
  )  
};
Amoolya S Kumar
  • 1,458
  • 9
  • 10