Iterar por meio de objetos aninhados em React.js

Se você já trabalhou com APIs, sabe que a estrutura dos dados que elas retornam pode se complicar rapidamente.

Imagine que você chame uma API de seu projeto React e a resposta seja mais ou menos assim:

Object1 { Object2 { propertyIWantToAcess: anotherpropertyIWantToAcess: } }

Você armazenou os dados no estado do seu componente como this.state.myPostse pode acessar os elementos do objeto externo com o seguinte:

render() { console.log(this.state.myPosts); const data = this.state.myPosts; const display = Object.keys(data).map((d, key) => { return ( 
  • {data.current_route}
  • ); }); return(
      { display }
    ); }

    Mas o problema é que você não consegue acessar nenhum dos objetos internos.

    Os valores dos objetos internos sempre mudarão, então você não pode codificar suas chaves e iterar por elas para obter os valores apropriados.

    Soluções possíveis

    Pode ser difícil trabalhar diretamente com respostas complexas de API, então vamos voltar um pouco e simplificar:

    const visit = (obj, fn) => { const values = Object.values(obj) values.forEach(val => val && typeof val === "object" ? visit(val, fn) : fn(val)) } // Quick test const print = (val) => console.log(val) const person = { name: { first: "John", last: "Doe" }, age: 15, secret: { secret2: { secret3: { val: "I ate your cookie" } } } } visit(person, print) /* Output John Doe 15 I ate your cookie */

    A lodashbiblioteca possui métodos simples para realizar a mesma coisa, mas esta é uma maneira rápida e suja de fazer a mesma coisa no vanilla JS.

    Mas digamos que você queira simplificar ainda mais, algo como:

    render() { // Logs data console.log(this.state.myPosts); const data = this.state.myPosts; // Stores nested object I want to access in posts variable const posts = data.content; // Successfully logs nested object I want to access console.log(posts); // Error, this will not allow me to pass posts variable to Object.keys const display = Object.keys(posts).map(key => {posts[key]} ) return( {display} ); }

    Mas você obtém um erro, TypeError: can't convert undefined to object errorsempre que tenta passar postspara Object.keys.

    Lembre-se de que esse erro não tem nada a ver com React. É ilegal passar um objeto como filho de um componente.

    Object.keys()retorna apenas as chaves do objeto que é passado como parâmetro. Você precisará chamá-lo várias vezes para iterar por todas as chaves aninhadas.

    Se você precisar exibir todo o objeto aninhado, uma opção é usar uma função para converter cada objeto em um componente React e passá-lo como uma matriz:

    let data= [] visit(obj, (val) => { data.push(

    {val}

    ) // wraps any non-object type inside

    }) ... return {data}

    Pacotes úteis

    Outra opção é usar um pacote como json-query para ajudar a iterar pelos dados JSON aninhados.

    Esta é uma versão modificada da renderfunção acima usando json-query:

     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 ( 

    Author: {author[i]}

    Title: {title[i]}

    Pending Payout: {pendingPayout[i]}

    Votes: {netVotes[i]}

    ); }); return ( {display} ); } }