ReactJS children - filter out null values

Viewed 13473

I'm rendering my components with:

<PanelGroup>
    {this.renderPanel1()}
    {this.renderPanel2()}
    {this.renderPanel3()}
</PanelGroup>

Now one of my panels is only available if its available-property is set to true. The render()-method otherwise returns null.

My <PanelGroup> should add a divider on the bottom of all elements except in the last element.

I tried to accomplish that with the following code, but because even if panel2 is returning null, the divider is still added, and the code won't work.

How can I filter out all my panels which are returning null? :)

<div>
   {React.Children.map(
       React.Children.toArray(props.children),
           (child: React.ReactElement<PanelProps>, i) => {
               return (
                     <div>
                        {React.cloneElement(child as React.ReactElement<PanelProps>, child.props)}
                        {/*Add divider after all elements except last*/}
                        {i < React.Children.count(props.children) -1 && <Divider/>}
                     </div>
                )
           }
        )}
</div>
3 Answers

You have to take advantage of Array.filter():

const MyComponent = ({ children }) => {
  // This filter will return only not null values
  const children = React.Children.toArray(children).filter(Boolean);
  
  // return ...
};

Working example:

const array = [1,2,3,null,4,null,5,null];
console.log(array.filter(Boolean));

children is not an array and cannot be treated as such (except by React.children).

If you try to filter nulls using standard Array techniques it will not work !

I just lost some time to this.

The issue I had was that I was treating children as an array, then doing some ramda reject all the nulls, and it wouldn't work.

As soon as I did a React.children.toArray(children) as the input to my "reject the nulls" filter all was well.

Imagine 2 children, where one was null, generated from something like this:

<PanelGroup>
    {this.renderPanel1()}
    {false && this.renderPanel2()}
</PanelGroup>

In my panel group renderer:

console.log(children.length) // 2
console.log(R.reject(R.isNil, children).length) // 2
console.log(R.reject(R.isNil, React.Children.toArray(children)).length) // 1

yields:

2
2
1

HTH

Instead of

{i < React.Children.count(props.children) -1 && <Divider/>}

i tried

{i < React.Children.toArray(props.children).length - 1 && <Divider/>}

thats working. toArray removes null values.

Related