简体   繁体   中英

How can I render nested JSON in react.js?

My data looks like this:

  "stats": {
    "offset": 0,
    "count": 1
  },
  "entries": [{
    "context": "time_latitude_longitude",
    "classifiers": {
      "station": "keca2"
    },
    "axes": {
      "time": "2014-01-01T00:00:00",
      "longitude": -131.625,
      "latitude": 55.33100128173828
    },
    "data": {
      "wave_height": null,
      "sea_surface_temperature": 6.599999904632568,
    }
  }]
}

And here is my code:

          <h1>Buoy Detail Page</h1>
            {buoy.entries.map((entry, i) => {
                return (
                    <>
                        <div key={i}>Station ID: {entry.classifiers.station}</div>
                        
                        <div key={i}>Sea Surface Temperature: {Math.floor(entry.data.sea_surface_temperature)} degrees C</div>
                        <div key={i}>Wave Height: {entry.data.wave_height} meters</div>

How can I rewrite that first div to get the value of 'keca2' to render on my page? I figured I just have to use another array iterator, but it seems like a waste. Is there a dryer way to do this?

If you are looking for a DRY er way to render the nested data and the nested entries array will only ever have a single element in it then you can use a combination of array access and Optional Chaining.

<h1>Buoy Detail Page</h1>
<div>Station ID: {buoy.entries?.[0]?.classifiers.station}</div>
<div>
  Sea Surface Temperature: {Math.floor(buoy.entries?.[0]?.data.sea_surface_temperature)} degrees C
</div>
<div>Wave Height: {buoy.entries?.[0]?.data.wave_height} meters</div>
        

If the entries property will ever have more than an single element in it then the optimal pattern is to just map that array to the JSX you want to render. Remember to place the react key on the outer-most mapped element, ie the Fragment in this case.

<h1>Buoy Detail Page</h1>
{buoy.entries.map((entry, i) => {
  return (
    <Fragment key={i}> // <-- React key goes here!
      <div>Station ID: {entry.classifiers.station}</div>
      <div>
        Sea Surface Temperature: {Math.floor(entry.data.sea_surface_temperature)} degrees C
      </div>
      <div>Wave Height: {entry.data.wave_height} meters</div>
    </Fragment>
  );
})}

I ended up flattening this object in my controller, per one of the suggestions in the comments, like this:

const BASE_URL = 'http://api.planetos.com/v1/datasets/noaa_ndbc_stdmet_stations/stations/';
const apikey = process.env.REACT_APP_PLANET_OS_KEY;

module.exports = {
    show,
};

const flattenObject = (obj) => {
    const flattened = {};
    Object.keys(obj).forEach((key) => {
        if (typeof obj[key] === 'object' && obj[key] !== null) {
            Object.assign(flattened, flattenObject(obj[key]));
        } else {
            flattened[key] = obj[key];
        }
    });
    return flattened;
};

async function show(req, res) {
    fetch(`${BASE_URL}${req.params.id}?apikey=${apikey}&time_order=desc`)
        .then(res => res.json())
        // .then(json => res.json(json))
        .then(data => {
            data = flattenObject(data);
            // console.log(data);
            res.json(data);
        })
        .catch(err => res.json(err))
};

Afterwards it was just a matter of accessing the new 1d object to render the data like this:

<div>Station ID: {buoy['node:station']}</div>
<div>Latitude: {buoy['latitude'].toFixed(2)}</div>

etc...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM