1

I am having issues with trying to access the values in this JSON response from wagtail CMS:

{
  "meta": {
    "total_count": 1
  },
  "items": [
    {
      "id": 13,
      "meta": {
        "type": "home.HomePage",
        "detail_url": "http://localhost/api/v2/pages/13/",
        "html_url": "http://localhost/frontpage/",
        "slug": "frontpage",
        "first_published_at": "2019-10-07T03:48:09.199838Z"
      },
      "title": "FrontPage",
      "body": [
        {
          "type": "heading",
          "value": "hello",
          "id": "44ab7cbf-24ce-4db1-8822-9a24e91385d9"
        },
        {
          "type": "paragraph",
          "value": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed et leo ac  velit venenatis elementum. Duis viverra velit eget justo consectetur  feugiat. Curabitur congue orci orci, vel iaculis augue pharetra nec.  Cras sit amet enim eu massa varius congue. Maecenas et tellus vitae urna  blandit ullamcorper sed in erat. Nam tristique justo vel ipsum  imperdiet, quis tempus enim euismod. Nunc eget condimentum neque, in  pretium elit. Proin tincidunt viverra nulla id blandit. Duis nec diam  tristique massa euismod varius quis ac ex. Suspendisse potenti. </p>",
          "id": "f5913d9e-294c-4f45-9147-909bec1f404c"
        },
        {
          "type": "paragraph",
          "value": "<p>Nulla sollicitudin mauris in turpis faucibus feugiat. Praesent vel neque  vitae erat tempor semper faucibus non magna. Vestibulum velit risus,  tempor at ultricies quis, auctor vitae augue. Vestibulum sit amet  porttitor tortor, ut tempor nisi. Sed nulla lacus, sodales eu risus eu,  tincidunt tempor quam. Mauris fringilla vitae est vitae hendrerit. In  facilisis libero in sagittis iaculis. Aenean ultrices elit tincidunt,  interdum metus vel, finibus mi. Aenean tincidunt purus ac mauris  hendrerit hendrerit. Phasellus sit amet ipsum nisl. Fusce in nisi  feugiat, condimentum lectus sit amet, sollicitudin dolor. Nulla  vulputate, felis scelerisque lobortis ornare, nisl sapien convallis  felis, ut scelerisque est purus vitae ipsum. </p>",
          "id": "f3769b82-5cad-4be7-a179-5800e24e6347"
        }
      ]
    }
  ]
}

For testing purposes, I am getting a response from the backend using this code:

class HomePage extends Component {
  constructor(props) {
    super(props);

    this.state = {
        home: [],
    };
  }

  componentDidMount() {
    this.getHome();
  }

  getHome() {
      axios
        .get('http://127.0.0.1:8000/api/v2/pages/?type=home.HomePage&fields=body')
        .then(res => {
            this.setState({home: res.data});
        })
        .catch(err => {
            console.log(err);
        });
  }

    render() {
        const { classes } = this.props;
        return(
            <div>
              {Object.entries(this.state.home).map(([key, value]) =>
                  <p>{key} : {value}</p>
              )}
            </div>
        )
    }
}

The error I get after compiling is :

Objects are not valid as a React child (found: object with keys {total_count})

So I try to go one level deeper with this.state.home.meta.total_count

React responds: TypeError: this.state.home.meta is undefined

Any idea on what's going on here, or if there is a better way to access this data?

3 Answers 3

2

Your render function will not render an object because it is not a text or a valid React child as the error message states.

If you still want to see it being printed out though, you can always convert it to JSON again just for viewing purposes.

 render() {
    const { classes } = this.props;
    return(
        <div>
          {Object.entries(this.state.home).map(([key, value]) =>
              <p>{key} : {typeof(value) === 'object' ? JSON.stringify(value) : value}</p>
          )}
        </div>
    )
}

Check the code here:

Edit laughing-wozniak-07lsx

The second problem you were having, when you tried to go one level deep by changing it to this.state.home.meta.total_count, it's because home.meta.total_count does not exist in the first time your component renders, only after componentDidMount is called, so make sure to check your variables and see if they're not null or undefined before using them.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for the response, this worked great. Is this considered bad practice to use this to assign the values to elements? E.g: grabbing just "hello" or values from the paragraphs?
@boostedd, I don't see that as a bad practice, but if you know what you're looking for, you could always treat that data in the getHome function, then set your state with that treated data, so your render knows exactly what to look for and you don't have to go down in different levels in your render. I updated my answer as well as the code too regarding going down into deeper levels in your state object.
Thanks again! You gave me some good code to study and found a good solution to my problem.
0

You have to add some extra checks to account for nested objects. Something recursive like this:

renderValues = (values) => {
  if (values) {
    return (
      <div>
        {values.map((value, key) => {
           if (typeof value === 'object') {
              return this.renderValues(value);
           }
           return <p>{key} : {value}</p>;
        })}
      </div>
    );
  }
  return null;
}

render() {
  return (
    <div>
      {this.renderValues(Object.entries(this.state.home))}
    </div>
  )
}

Comments

0

Your component mounts but you don't have the response from the API yet. You need to wait for your API response to complete and then access your data values.

Try this:-

class HomePage extends Component {
  constructor(props) {
    super(props);

    this.state = {
        home: [],
        isLoading: true
    };
  }

  componentDidMount() {
    this.getHome();
  }

  getHome() {
      axios
        .get('http://127.0.0.1:8000/api/v2/pages/?type=home.HomePage&fields=body')
        .then(res => {
            this.setState({home: res.data, isLoading: false});
        })
        .catch(err => {
            this.setState({isLoading: false});
            console.log(err);
        });
  }

    render() {
        const { classes } = this.props;
        return(
            isLoading && (
                <div>
                  {Object.entries(this.state.home).map(([key, value]) =>
                      <p>{key} : {value}</p>
                  )}
                </div>
            )
        )
    }
}

And DO NOT render directly an object inside the JSX (as you are doing it currently). Try to add proper logic to traverse that res.data. Otherwise, you will see that error : Objects are not valid as a React child

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.