简体   繁体   中英

React iterate nested arrays/objects with map. Is return mandatory to render each map function?

I'm new to React. I'm building a small function component that renders the weaknesses of a Pokemon.

It takes the type of the Pokemon stored in the state (pokemonState.types) as an array of objects for each type, compare the type to a JSON file containing all the type effectiveness (see below).

types_data.json

  "electric": {
"attack": {
  "double": ["flying", "water"],
  "half": ["dragon", "electric", "grass"],
  "zero": ["ground"]
},
"defense": {
  "half": ["electric", "flying", "steel"],
  "double": ["ground"],
  "zero": []
}

To get the data I want, I need to do several iterations and I noticed my component only renders when I specify the return keyword and wrap my element in a HTML tag.

Function that doesn't render anything (but console.log doesn't return undefined)

  const pokemonTypeChart = () => {
if (!_.isEmpty(pokemonState)) {
  const allTypes = Object.entries(types_data);
  const typeEffectiveness = allTypes.map(([key, value]) => {
    pokemonState.types.map((el) => {
      if (el.type.name === key) {
        console.log(key, value);
        return <p>{el}</p>;
      }
    });
  });
  return (
    <div>
      <h1>Test</h1>
      <p>{typeEffectiveness}</p>
    </div>
  );
}};

Function that works well:

const pokemonTypeChart = () => {
if (!_.isEmpty(pokemonState)) {
  const allTypes = Object.entries(types_data);
  return (
    <div>
      <h1>Type Effectiveness</h1>
      {allTypes.map(([key, value]) => {
        return (
          <>
            {pokemonState.types.map((el, i) => {
              if (el.type.name === key)
                return <h3 key={i}>{value.defense.double}</h3>;
            })}
          </>
        );
      })}
    </div>
  );
}};

My question are:

  • For the function that doesn't render anything, the problem is that I don't use return after each iteration right?
  • Is my second function good practice in this scenario? is there a cleaner way I should I have wrote it?

Thanks for your help.

The reason why your first function isn't working is that you are returning <p>{el}</p> .

el is equal to an object & you are expecting a string.

Specifically, in this case, it is something like {type:{name: "electric"}

If you change that line from return <p>{el}</p>; to return <p>{el.type.name}</p>; , then that fixes our inner .map , so you are getting closer.

However, you've also got a second problem... the outer .map function is not returning anything. Your typeEffectiveness variable is what we're ultimately rendering, and that variable is equal to the result from calling allTypes.map . While your nested pokemonState.types.map function is getting returned to the parent .map function, your parent .map function does not have a return statement.

Ultimately, you are rendering {typeEffectiveness} , so we've gotta make sure that variable is an array of react elements that will render to the DOM.

There were a couple other minor issues as well. Namely, we have to remove the paragraph tags <p>{typeEffectiveness}</p> here or we'd end up with nested p tags, since each item in the typeEffectiveness list is already enclosed in <p></p> .

Finally, you should add key tags to your list items as well. <p key="{el.type.name}">{el.type.name}</p>

Dig into the documentation on Lists & Keys here: https://reactjs.org/docs/lists-and-keys.html

The following code is a debugged version of your first function.

I also included a refactored version of your section function below. It would be fairly inefficient to map through the entire types_data object entries, when we really only care about the types present in our pokemonState , so take a look at my approach to that below as well.

 const e = React.createElement; const pokemonState ={types: [{type:{name: "electric"}}]}; let types_data = { "electric": { "attack": { "double": ["flying", "water"], "half": ["dragon", "electric", "grass"], "zero": ["ground"] }, "defense": { "half": ["electric", "flying", "steel"], "double": ["ground"], "zero": [] } } }; const PokemonTypeChart = () => { if (!_.isEmpty(pokemonState)) { const allTypes = Object.entries(types_data); const typeEffectiveness = allTypes.map(([key, value]) => { return (pokemonState.types.map((el) => { if (el.type.name === key) { return ( <p key="{el.type.name}">{el.type.name}</p> ); } })); }); return ( <div> <h1>Test</h1> {typeEffectiveness} </div> ); }}; const domContainer = document.querySelector('#pokemon'); ReactDOM.render(e(PokemonTypeChart), domContainer);
 <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/underscore@1.13.1/underscore-umd-min.js"></script> <div id="pokemon"></div>

 const e = React.createElement; const pokemonState ={types: [{type:{name: "electric"}}]}; let types_data = { "electric": { "attack": { "double": ["flying", "water"], "half": ["dragon", "electric", "grass"], "zero": ["ground"] }, "defense": { "half": ["electric", "flying", "steel"], "double": ["ground"], "zero": [] } } }; const PokemonChart = () => { if (!_.isEmpty(pokemonState)) { const plistItems = pokemonState.types.map((item) => types_data[item.type.name].defense.double.map((i) => <p key={i}>{i}</p> )); return ( <div> <h1>Type Effectiveness</h1> {plistItems} </div> ); }}; const domContainer = document.querySelector('#pokemon'); ReactDOM.render(e(PokemonChart), domContainer);
 <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/underscore@1.13.1/underscore-umd-min.js"></script> <div id="pokemon"></div>

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