Reputation: 3238
In React, to render a list you generally map
over and render elements like this:
list.map((itm, idx) => <li>{itm}</li>)
Can I refactor this to a component that is generic enough to handle different element types but still do the mapping for me? Aka,
<EasyList data={list} /> // tag would be "li" by default
<EasyList data={list} tag="p" /> // a customized tag name
What would be the best way to implement something like this?
Upvotes: 1
Views: 71
Reputation: 81006
This answer isn't much different than John Ruddell's, but I had already completed it before seeing his.
You can make this EasyList
component as sophisticated as you need it to be. My example below shows that you can have it control the parent component (ul
by default) and that the component types passed can be html element types (e.g. ul
, li
, p
) or custom components such as DivWithHeaderText
in my example.
import React from "react";
import ReactDOM from "react-dom";
const EasyList = ({ data, ListComponent = "ul", ItemComponent = "li" }) => {
return (
<ListComponent>
{data.map(item => (
<ItemComponent>{item}</ItemComponent>
))}
</ListComponent>
);
};
const myItems = ["Here", "are", "my", "list", "items"];
const DivWithHeaderText = ({ children }) => {
return (
<div style={{ border: "solid black 1px" }}>
<div>Here is my header</div>
<hr />
{children}
</div>
);
};
function App() {
return (
<>
<EasyList data={myItems} />
<EasyList
data={myItems}
ListComponent={DivWithHeaderText}
ItemComponent="p"
/>
</>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Upvotes: 0
Reputation: 25842
You can achieve exactly what you are describing in the way you are describing it. The implementation of EasyList
could look something like this
const EasyList = ({data, tag: Elem = 'li'}) => {
return data.map( (item, idx) => <Elem key={idx}>{item}</Elem>)
}
and usage would look like
<EasyList data={list} /> // tag would be "li" by default
<EasyList data={list} tag="p" /> // a customized tag name
There are multiple ways you could implement this, so depending on needs you could go the route of a render
prop, where you define the exact elements you need. Really it depends on what kind of control / granularity you want.
<EasyList data={seed} render={ (item, idx) => <li>{item}</li>} />
and the implementation with a render prop would look like
const EasyList = ({data, render}) => {
return data.map(render)
}
Upvotes: 2