stacks icon indicating copy to clipboard operation
stacks copied to clipboard

Stack component should not apply spacing around empty components

Open jsamr opened this issue 3 years ago • 8 comments

If a children of Stack renders conditionally, e.g. returns null on some instances, it would be expected that spaces are not added between this component and its siblings. However I don't know how easy it would be to feature given the current implementation. You would certainly have to inspect the children of the element.

function Empty() {
  return null;
}

jsamr avatar Apr 30 '21 22:04 jsamr

hey @jsamr, I'm looking into it, however, I think with the current implementation (that isn't based on cloneElement) and how react works, it isn't trivial. I'm aware that it's a common case, so I will try to provide a solution to fix this issue :)

mobily avatar May 06 '21 19:05 mobily

What about using Hidden component with some conditional prop?

let visible = true

<Stack>
  <SomeElement/>
  <SomeElement/>
  <Hidden isVisible={visible}> // isVisible by default = false
    <AnotherElement/>
  </Hidden>
</Stack>

However I'm not sure if this wouldn't be harder to implement :D

Fortidude avatar May 06 '21 20:05 Fortidude

@Fortidude We could also write

<Stack>
  <SomeElement/>
  <SomeElement/>
  {isVisible && <AnotherElement/>}
</Stack>

and that would be fine with Stack, since falsy values are not accounted as children. If the controlling component (the one rendering Stack) has prior knowledge on the conditions to render or not render a child, we're fine. My use case is when <AnotherElement /> conditions to render are invisible to the controlling component. For example, when using a global store, context and hooks.

jsamr avatar May 06 '21 20:05 jsamr

A naive implementation of Stack with such feature:

import React, { Children } from "react";
import View from "react-native";

function shouldIncludeNode(element) {
  if (element && typeof element === "object") {
    return Children.toArray(element.children).some(shouldIncludeNode);
  }
  return !!element;
}

export default function Stack({ children, style }) {
  return (
    <View style={style}>
      {Children.toArray(children)
        .filter(shouldIncludeNode)
        .map((c) => (
          <View style={{/** conditional margins */}}>{c}</View>
        ))}
    </View>
  );
}

jsamr avatar May 06 '21 20:05 jsamr

We face the same problem. We let our components decide if they should be rendered or not. It would be a big refactor to move that logic out into the screen. I too wish the Stack (and other components) would check if their children return null

oliverdolgener avatar Jun 24 '21 11:06 oliverdolgener

Anyone figure out how to handle this case?

cheunjm avatar Jun 01 '22 18:06 cheunjm

Could flex-gap support in RN 0.71.0 solve this issue? https://github.com/facebook/react-native-website/pull/3398

happyfloat avatar Nov 15 '22 15:11 happyfloat

@happyfloat hopefully yes! I have been waiting for the flex gap support for so long, and once it's published I will investigate as soon as possible if that solves this issue

mobily avatar Nov 16 '22 14:11 mobily