Iterate through nested object in React.js

what output do you want to show? The sandbox I posted above posts all of the users posts, with date, URL and body. It’s not pretty but if that’s what you want it’s in there.

What you describe in your post is exactly what I did. I struggled as well, but it’s some inverse weird thinking to get it to work.

Compare my code to what yo want to do…you have describe exactly what I did (I think)

I have ot be honest it hurt my brain to sort that out, but it was a fun challenge.

Hey guys thanks again for all the help working through this.

I found a very useful package that helps iterate through nested JSON data. Check this out if you need to do something like this in the future. It called json-query and it very simple.

Here’s the render function of my project and how I implemented json-query and simplified things:

 render() {
   const utopian = Object.keys(this.state.utopianCash);
   console.log(this.state.utopianCash);

   var author = jsonQuery('[*][author]', { data: this.state.utopianCash }).value
   var title = jsonQuery('[*][title]', { data: this.state.utopianCash }).value
   var payout = jsonQuery('[*][total_payout_value]', { data: this.state.utopianCash }).value
   var postLink = jsonQuery('[*][url]', { data: this.state.utopianCash }).value
   var pendingPayout = jsonQuery('[*][pending_payout_value]', { data: this.state.utopianCash }).value
   var netVotes = jsonQuery('[*][net_votes]', { data: this.state.utopianCash }).value


   let display = utopian.map((post, i) => {
     return (
       <div className="utopian-items">
        <p>
          <strong>Author: </strong>
          {author[i]}
        </p>
        <p>
          <strong>Title: </strong>
            <a href={`https://www.steemit.com` + postLink[i]}>{title[i]}</a>
        </p>
        <p>
          <strong>Pending Payout: </strong>
            {pendingPayout[i]}
        </p>
        <p>
          <strong>Votes: </strong>
          {netVotes[i]}
        </p>
       </div>
     );
   });

    return (
      <div className="utopian-container">
        {display}
        <User />
      </div>
    );
  }
}```

Hi, I have a noob issue but I can’t access to my State Objects, do you have any idea?
Captura de pantalla 2020-05-19 a la(s) 17.34.06

You’ll need to post some code: it’s not possible to see what your trying to do here

Hi there, here is my code:

class BitsoApi extends React.Component{
    state = {
        btc_mxn: [],
        btc_usd:[]
    };

    async componentDidMount() {
       
        const firstrequest = "https://cors-anywhere.herokuapp.com/https://api.bitso.com/v3/ticker/?book=btc_mxn";
        const secondrequest = "https://cors-anywhere.herokuapp.com/https://api.bitso.com/v3/ticker/?book=btc_usd";

        // Make first two requests
        const [firstResponse, secondResponse] = await Promise.all([
          axios.get(firstrequest),
          axios.get(secondrequest)
        ]);
      
        this.setState({
          btc_mxn: firstResponse.data,
          btc_usd: secondResponse.data
        });
      
      }
      render(){
        let myData = (this.state) || {};
        console.log(myData.btc_mxn.payload.last);// Here last is not working

        const display = Object.keys(myData).map((key,i) => {
            console.log(key);
                return (
                <div className="my-posts">
                    <li>
                        <span>Key Name: "I need here the info from the state"</span>
                    </li>
                </div>
                );
            
        });

        
        return(
            <div>
              <ul>
                { display }
              </ul>
            </div>
          );
    }
};

I can access to this information but then I can’t render each component of the object :confused:

  • the state has two properties (Object.keys gets you the keys)
  • this.state[key] gives you the values

Thank you Dan, but I don’t get the result that I want, this is my code:

render(){
        let myData = (this.state.btc_mxn) || {};
        //console.log(myData.btc_mxn.payload);// here I've received from console()

        if (this.state.length === 0) {
            return null;
        }

        const display = Object.keys(myData).map((key, value) => {
            console.log(myData[key]);
            /* I see on console:
            true
            BitsoApi.js:37 {high: "222500.00", last: "207544.24", created_at: "2020-05-21T23:51:49+00:00", book: "btc_mxn", volume: "569.34086668", …}
            */

How can I print on a html tag each element of the myData[key]??

So the state is an object

{
  btx_mxn: // one value
  btx_usd:  // another value
}

The values for those seem to be objects, so it looks something like

{
  btx_mxn: {high: "222500.00", last: "207544.24", created_at: "2020-05-21T23:51:49+00:00", book: "btc_mxn", volume: "569.34086668"},
  btx_usd: {high: "222500.00", last: "207544.24", created_at: "2020-05-21T23:51:49+00:00", book: "btc_mxn", volume: "569.34086668"},
}

React doesn’t do anything special here, it just works like JS, because it is JS. You access objects as you would anywhere else in JS, and that’s what you aren’t doing.

This, then, doesn’t seem to be correct:

class BitsoApi extends React.Component{
    state = {
        btc_mxn: [],
        btc_usd:[]
    };

You are saying they are arrays when AFAICS they aren’t (please correct me if I’m wrong)

So as a simplified example (this is not complete, you’ll need to do a bit more work):

So you can write a component (this is exactly equivalent to what you’re doing with the display bit of the code, but it’s generally easier to split the logic down). It will be a list item. I’ll just pull out two of the values, I don’t know how you want to display this data. I’m just using made-up names as well, call it something better:

function BtxItem (btxItem) {
  return (
    <li>
      <p>High: {btxItem.high}</p>
      <p>Last: {btxItem.last}</p>
    </li>
  );
}

If you give that function one of the results, it will create a list item that renders the values I’ve said it should render.

Then in your main component, you want to render a list item for each result:

class BitsoApi extends React.Component{
  state = {
    btc_mxn: null,
    btc_usd: null,
  };

  // rest of the logic to get the data here

  render() {
    return (
      <ul>
        { Object.values(this.state).map((item) => <BtxItem btxItem={item} />) } 
      </ul>
    );
  }
}

Do you see how this hangs together?

Thank you! this is awesome, but I still have an error, when I call the function like you explain, it works in console:

function BtxItem (btxItem) {
    console.log(btxItem); // here it works, show you an image.
    return (
      <li>
        <p>High: {btxItem.high}</p>
        <p>Last: {btxItem.last}</p>
      </li>
    );
  }

But when I try to call the btxItem.high I get an “Undefined” result, do you know why?

1 Like

So the issue I think is that the data isn’t there when you render: you’re making an asynchronous call, and it tries to render before that call completes. Try this:

function BtxItem (btxItem) {
    console.log(btxItem); // here it works, show you an image.
    return btxItem ? (
      <li>
        <p>High: {btxItem.high}</p>
        <p>Last: {btxItem.last}</p>
      </li>
    ) : null;
  }

What I’m doing is saying "if the btxItem is defined (eg the data has arrived), render the list item, otherwise render null"

React allows you to return null when you render, and it just renders nothing if that’s the case. So this will render nothing, then as soon as there is data, the props will change, and the component will rerender with the data.

Almost there!
On Console it works fine, but I still can’t display the result, I’ve changed the code because I have many get requests, I don’t know if that is the right way, but I’ve made this:

class HomeContainer extends React.Component{
    state = {
        stateBooks: [],
    };

    componentDidMount(){
        const books = [
            "btc_mxn", "btc_usd", "eth_mxn", "xrp_mxn", "ltc_mxn", "tusd_mxn", "mana_mxn", "gnt_mxn", "bat_mxn", "dai_mxn"
        ];
        
        const url = "https://cors-anywhere.herokuapp.com/https://api.bitso.com/v3/ticker/?book="
        for (const [index, value] of books.entries()) {
            const newLocal = "XMLHttpRequest";
            axios.get(url+value, {
                mode: 'no-cors',
                secure: false,
                headers:{
                    "X-Requested-With": newLocal
                } 
            })
            .then(result => {
                const stateBooks = result.data.payload
               // console.log(stateBooks);
                this.setState({ stateBooks });
                //this.state.push({ stateBooks: stateBooks})

            }).catch(function(error) {
                if (!error.response) {
                  // network error
                  console.log("Network error");
                } else {
                  // http status code
                  const code = error.response.status
                  // response data
                  const response = error.response.data
                }
              });

          }


    }
    render() {
        return (
          <ul>
            { Object.values(this.state).map((item) => <BtxItem btxItem={item} />) } 
          </ul>
        );
      }

Now what do you thing is missing to display the result?

Well here is my complete code but the last result on console is “undefined”, don’t know why…

import React, {Component} from 'react';
import axios from 'axios';


function BtxItem (btxItem) {
    console.log(btxItem);//here I get {btxItem: undefined}
    return btxItem ? (
        <div className="my-posts">
            <li>
                {btxItem.last}
            </li>
            <li>
                {btxItem.high}
            </li>
            <li>
                {btxItem.book}
            </li>
        </div>
    ) : null;
  };
    

class HomeContainer extends React.Component{
    state = {
        stateBooks: [],
    };

    async componentDidMount(){
        const books = [
            "btc_mxn", "btc_usd", "eth_mxn", "xrp_mxn", "ltc_mxn", "tusd_mxn", "mana_mxn", "gnt_mxn", "bat_mxn", "dai_mxn"
        ];
        
        const url = "https://cors-anywhere.herokuapp.com/https://api.bitso.com/v3/ticker/?book="
        for (const [index, value] of books.entries()) {
            const newLocal = "XMLHttpRequest";

            const [Response] = await Promise.all([
                axios.get(url+value, {
                    mode: 'no-cors',
                    secure: false,
                    headers:{
                        "X-Requested-With": newLocal
                    } 
                })]);

            this.setState({
               stateBooks: Response.data.payload,
            });

          }


    }
    render() {
        console.log(this.state);
        /*Here I get the object:
        {stateBooks: {…}}
            stateBooks:
            ask: "197099.95"
            bid: "196511.00"
            book: "btc_mxn"
            change_24: "-4500.01"
            created_at: "2020-05-26T22:03:43+00:00"
            high: "201940.27"
            last: "196511.00"
            low: "194216.43"
            volume: "267.95771882"
            vwap: "197410.8318200617"
            __proto__: Object
            __proto__: Object*/
        return (
          <ul>
            { Object.values(this.state).map((item) => <BtxItem btxItem={item.stateBooks} />) } 
          </ul>
        );
      }
   
}

export default HomeContainer;