Reputation: 8408
I am trying to create a function that does nothing else than map through a list. This function is always the same, but the list item fields (Fields) can change. So I am trying to pass Fields to the map function, so that I can reuse the map function (List and Item) and only change Fields.
Here is an example of the code I wrote. It works as is, but I don't know how to store the map function somewhere else where it can be reused between multiple similar components.
const Fields = (props) => {
return (
<Fragment>
<MediaGroup { ...props } />
<TextRich { ...props } />
<LinkGroup { ...props } />
</Fragment>
);
}
const Item = (props) => {
return (
<PanelBody title={ `Item ${props.index + 1}` } initialOpen={ false }>
<PanelRow>
<RmListItemMarkup { ...props } />
<Fields { ...props } />
</PanelRow>
</PanelBody>
);
}
export const List = (props) => {
const { attr } = props;
return (
<Fragment>
<PanelBody title={ __('Content List') } initialOpen={ true }>
<AddListItemMarkup { ...props } />
</PanelBody>
{ (attr && attr.length) ? attr.map((item, index) => <Item key={ index } index={ index } { ...props } />) : null }
</Fragment>
);
}
Ideally I would like List and Item to live it its own file and simply import them from the file that holds Fields. That way I could customize Fields and pass to List without having to repeat List and Item inside the same file. In fact, List and Item could technically be the same function, all I would need to pass is Fields.
Please, let me know if you know any solutions for this. Thanks in advance!
Upvotes: 1
Views: 71
Reputation: 39250
One way to do it is using a HOC:
const ItemType1 = (props) => (
<div>
<div>item type 1</div>
<pre>{JSON.stringify(props, undefined, 2)}</pre>
</div>
);
const ItemType2 = (props) => (
<div>
<div>item type 2</div>
<pre>{JSON.stringify(props, undefined, 2)}</pre>
</div>
);
const ItemHoc = (ItemType) => (props) => (
<ItemType {...props} />
);
const ListHoc = (Item) => ({ items }) => (
<ul>
{items.map((item, index) => (
<Item key={index} item={item} />
))}
</ul>
);
const Type1List = ListHoc(ItemHoc(ItemType1));
const Type2List = ListHoc(ItemHoc(ItemType2));
const App = () => {
const items = [1, 2, 3];
return (
<div>
<Type1List items={items} />
<Type2List items={items} />
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Another way is render props:
const ItemType1 = (props) => (
<div>
<div>item type 1</div>
<pre>{JSON.stringify(props, undefined, 2)}</pre>
</div>
);
const ItemType2 = (props) => (
<div>
<div>item type 2</div>
<pre>{JSON.stringify(props, undefined, 2)}</pre>
</div>
);
const Item = ({ Render, ...props }) => (
<Render {...props} />
);
const List = ({ items, ...props }) => (
<ul>
{items.map((item, index) => (
<Item key={index} item={item} {...props} />
))}
</ul>
);
const App = () => {
const items = [1, 2, 3];
return (
<div>
<List items={items} Render={ItemType1} />
<List items={items} Render={ItemType2} />
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Upvotes: 1