Is there any way I can include the wrapping div's FilterListContainer, FilterListScroll and FilterList in the map itself?
So if there is something to map, it will add the parent div's. If not it wont.
<FilterListContainer>
<FilterListScroll>
<FilterList>
{Object.keys(this.props.body_search_filter)
.map((k) => (
<SidebarFilter
key={k}
type={k}
filter={this.props.body_search_filter[k]}
handleChange={this.handleFilterChange}
/>
))
.filter(
(i) =>
i.props.filter.list.length > 0 &&
((!i.props.filter.optional && !i.props.filter.hidden) ||
(i.props.filter.list.length !== 1 &&
!i.props.filter.list[0].disabled))
</FilterList>
</FilterListScroll>
</FilterListContainer>
CodePudding user response:
You'll be able to use short-circuiting of logical operators here:
{Object.keys(this.props.body_search_filter).length && (
<FilterListContainer>
<FilterListScroll>
<FilterList>
{Object.keys(this.props.body_search_filter)
.map((k) => (
<SidebarFilter
key={k}
type={k}
filter={this.props.body_search_filter[k]}
handleChange={this.handleFilterChange}
/>
))
.filter(
(i) =>
i.props.filter.list.length > 0 &&
((!i.props.filter.optional && !i.props.filter.hidden) ||
(i.props.filter.list.length !== 1 &&
!i.props.filter.list[0].disabled))
</FilterList>
</FilterListScroll>
</FilterListContainer>
)}
But you might want to filter the list, then check if the filtered list has any elements instead:
const filtered = Object.keys(this.props.body_search_filter).filter((k) => {
const f = this.props.body_search_filter[k];
return f.list.length > 0 &&
((!f.optional && !f.hidden) ||
(f.list.length !== 1 && !f.list[0].disabled))
});
// ...
// then use 'filtered' instead
{filtered.length && (
<FilterListContainer>
<FilterListScroll>
<FilterList>
{filtered.map((k) => (
<SidebarFilter
key={k}
type={k}
filter={this.props.body_search_filter[k]}
handleChange={this.handleFilterChange}
/>
))}
</FilterList>
</FilterListScroll>
</FilterListContainer>
)}
CodePudding user response:
Moving my comment to an answer to add a snippet
You could do the map before the return. Then you can 'check' if the map has some content, if so, use it, otherwise, don't render (or use fallback)
Please see comments in code
const { useState } = React;
const Example = () => {
// Demo data
const [data, setData] = useState([ 'foo', 'bar' ])
// Filter Mapping logic
const mapped = data
.filter(d => d !== 'foobar')
.map(d => <li>{d.toUpperCase()}</li>);
// Content based on map, use it, or render 'null'
// The wrapped 'ul' is OP's FilterListContainer as an example
const content = !mapped.length ? null :
(
<div>
<ul>
{mapped}
</ul>
</div>
);
// Render
return content;
}
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>
