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>