59 votes

Comment avoir des boucles imbriquées avec map en JSX ?

Je n'arrive pas à avoir deux map imbriqués :

render() {
    return (

          {Object.keys(this.state.templates).map(function(template_name) {
            return (

              {this.state.templates[template_name].items.map(function(item) {
                return (

                )
              })}
            )
          })}

        Template: {template_name}{item.id}

    )
  }

Cela donne une SyntaxError: unknown: Unexpected token.

Comment imbriquer des appels map en JSX?

0 votes

Quelle version de React utilisez-vous ?

0 votes

@MattHolland React 16.1.1

82voto

Sagiv b.g Points 15448

Vous devez l'envelopper à l'intérieur d'un élément.

Quelque chose comme ceci (j'ai ajouté un tr supplémentaire en raison des règles des éléments de table) :

  render() {
    return (

          {Object.keys(templates).map(function (template_name) {
            return (

                {templates[template_name].items.map(function (item) {
                  return (

                  );
                })}

            );
          })}

                    Template: {template_name}

                      {item}

    );
  }
}

Exemple en cours d'exécution (sans une table) :

const templates = {
  template1: {
    items: [1, 2]
  },
  template2: {
    items: [2, 3, 4]
  },
};

const App = () => (

    {
      Object.keys(templates).map(template_name => {
        return (

            {template_name}
            {
              templates[template_name].items.map(item => {
                return({item})
              })
            }

        )
      })
    }

);
ReactDOM.render(, document.getElementById('root'));

5 votes

Oui, utiliser un élément pour envelopper les éléments a permis que cela fonctionne. Cependant, je n'ai pas exactement utilisé votre solution car les imbriqués ne sont pas valides, selon validator.w3.org/nu. À la place, j'ai enveloppé les éléments avec , et avoir plusieurs dans un seul tableau est du HTML valide (exemple : stackoverflow.com/a/3076790/3486743). Merci quand même.

1 votes

La clé ici est d'utiliser 2 déclarations return

8voto

aderchox Points 158

Je ne suis pas sûr que ce soit techniquement correct, mais comme un mnémonique, vous pouvez vous souvenir que : "Chaque élément JSX retourné doit être un seul élément JSX".

La plupart du temps, il suffit d'envelopper ce que vous avez dans une paire de balises <> (ou toute autre paire de balises arbitraire) pour résoudre le problème. Par exemple, si vous renvoyez deux

s depuis la méthode de rendu d'un composant, ce ne sera pas correct, cependant, si vous enveloppez ces deux dans une paire de <>, cela sera probablement résolu.

Mais notez que parfois cela peut devenir un peu plus vague, par exemple, en imbriquant deux maps ES6 l'une dans l'autre, par exemple :

{
  this.categorizedData.map(
    (catgGroup) => (

        {catgGroup}

      this.categorizedData[catgGroup].map(
        (item) => (

            {item.name}
            {item.price}

        )
      )
    )
  )
}

Peut être résolu comme ceci :

{
  this.categorizedData.map(
    (catgGroup) => (
      <> // <--- Remarquez ceci, il enveloppera tous les éléments JSX ci-dessous dans un seul élément JSX.

          {catgGroup}

        {this.categorizedData[catgGroup].map( // <--- Remarquez également ici, nous l'avons enveloppé entre accolades, car c'est une "expression" à l'intérieur de JSX.
          (item) => (

              {item.name}
              {item.price}

          )
        )}

    )
  )
}

P.S. : (De la documentation) Vous pouvez également renvoyer un tableau d'éléments à partir d'un composant React :

render() {
  // Pas besoin d'envelopper les éléments de liste dans un élément supplémentaire !
  return [
    // N'oubliez pas les clés :slight_smile:
    Premier élément,
    Deuxième élément,
    Troisième élément,
  ];
}

4voto

Lliam Scholtz Points 1

J'ai eu du mal pendant un certain temps à faire fonctionner ma fonction map imbriquée pour découvrir que ce que vous retournez est critique. Assurez-vous de retourner la deuxième map elle-même et pas seulement le résultat final attendu :

let { categories } = data;

categories = categories.map(category =>
    category.subcategories.map((subcategory, i) => {subcategory.name})
);

return (

        {categories}

);

0voto

rainkowla Points 26

Je pense que le problème est que le type de retour devrait être un tableau mais pas un objet dans React16. Vous pourriez essayer comme ceci ci-dessous:

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      templates: {
        foo: {
          items: [
            {id: 0},{id:1}
          ]
        },
        bar: {
          items: [
            {id: 2},{id:3}
          ]
        }
      }
    }
  }

  renderTemplate = (template, name) => {
    let data = []
    data = template.items
    data.unshift({ name: name })
    return data.map((item, index) => {item.name ? item.name : item.id})
  }

  render() {
    return (

          {Object.keys(this.state.templates).map(name => {
            return this.renderTemplate(this.state.templates[name], name)
          })}

    )
  }
}

ReactDOM.render(, document.getElementById('root'))

td {
  color: white;
  padding: 0 20px;
  background: grey;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X