Home > Software design >  Return completed map before rendering it in React
Return completed map before rendering it in React

Time:01-27

I have an a component that handles a list, and has some internal logic to determine if it should render as a ul, or as a div. If the list is empty, it renders as a div, and if the list has elements, it renders as a ul.

I'm making an API call to get the potential list of elements. When I loop through,

<ParentUlOrDiv>
  {data.map(el => {
    <div>test</div>
  })}
</ParentUlOrDiv>

The parent doesn't know the amount of elements it will have to render, so it plugs them all into one li, meaning that I'll get all sorts of visual misbehavior.

How can I return the complete, mapped list from data and pass that that to the ParentUlOrDiv as a child (as then it'd know the amount of elements it needs to render)?

CodePudding user response:

Solution1

create a new variable before the map function, and push each element into that variable as it's mapped over. Then you can pass that variable to the ParentUlOrDiv as a child. For example:

const childElements = [];

data.map(el => {
    childElements.push(<div>test</div>)
});

return (
  <ParentUlOrDiv>
     {childElements}
  </ParentUlOrDiv>
);

Solution2

use the useState hook to store the mapped elements and update the state with each iteration of the map function. Then you can pass the state variable to the ParentUlOrDiv as a child. For example:

const [childElements, setChildElements] = useState([]);

data.map(el => {
    setChildElements(prevElements => [...prevElements, <div>test</div>])
});

return (
  <ParentUlOrDiv>
      {childElements}
  </ParentUlOrDiv>
);

Both of these solutions will allow the ParentUlOrDiv component to know how many elements it will be rendering, and will prevent any visual misbehavior.

CodePudding user response:

Use props.children.length to choose between an ul or the div.


Example were the children are wrapped in a ul and li if there are more then 1. Otherwise, it's just rendered in a div

const ParentUlOrDiv = (props) => {
  console.log('ParentUlOrDiv got', props.children.length, 'children');
  
  const WrapElement = props.children.length > 1 ? 'ul' : 'div';
  
  const values = props.children.length > 1 ? props.children.map(c => <li>{c}</li>) : props.children;
  
  return <WrapElement>{values}</WrapElement>;
}

const Example = () => {
    
    const data = [
      'Foo', 'Bar'
    ]

    return (
        <ParentUlOrDiv>
            {data.map(d => <em>{d}</em>)}
        </ParentUlOrDiv>
    )
}
ReactDOM.render(<Example />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>

  • Related