View元素嵌套时每个View都必须显式指定flex:1?



  • 实际使用时遇到一个很伤脑筋的问题,在如下结构中,任何一层的View如不显式指定样式flex:1,那么这个View就会因大小为0而不显示(包括其子元素)
    <View>
    <View>
    ...
    </View>
    </View>
    因为这个问题的存在,在设计可复用组件时引起一些衍生问题。所以想问,有办法让View的默认flex为1吗?



  • 首先,View如果不指定flex:1,也没有显式指定宽高,则表示它应该根据它的子元素来确定它的大小。只有它没有子元素的时候,大小才会为0。 所以

    这个View就会因大小为0而不显示(包括其子元素)

    是不应该存在的现象,如果你观察到如此,请检查一下代码。

    其次,让View默认flex为1,也就是改变一个组件本身的默认行为,是反模式的,但你可以定义一个新的组件,譬如叫FlexView,使它的默认表现为一个flex为1的View,然后在你的其它代码中使用这个FlexView就好了。



  • @tdzl2003 你好!非常感谢你的详细解答!我现在的疑问是,对于你所说的FlexView的例子中,如果我需要的效果是这样来使用FlexView:
    <FlexView>
    ...这里有一些子组件,原生的或者自定义的
    </FlexView>
    那么,在编写FlexView这个组件本身的时候,大概就会这样render:
    render: function () {
    return <View style={{flex: 1}}>{this.props.children}<View>
    }
    更进一步,如果我需要在FlexView的render中,给this.props.children中的子组件分别添加特定的样式,则似乎只有通过遍历this.props.children同时通过React.cloneElement(child, {style: someNewStyle})来克隆出添加了样式的“子组件复制品”(因为this.props.children中的子组件不可修改)。
    这么说来,似乎在很多与样式有关的自定义组件中,需要不可避免地遍历this.props.children然后cloneElement?
    求解惑,谢谢!



  • @nsy1661 听起来大量cloneElement不像是一个合理的做法。即使这样做了,子元素的子元素 是否也要clone呢?所以我觉得给子组件添加样式这个需求本身就不合理。这也违反了React本身的思想:同一个组件,不管写在哪,都应当结果一致

    以下是文档中的说法:

    React组件在概念上被设计为强隔离性的:你应当可以在应用的任何位置放置一个组件,而且只要属性相同,其外观和表现都将完全相同。

    而你的这种给子元素添加样式的行为会打破这种思想。



  • @tdzl2003 我想了下,道理确实如您所说。只是实际应用的时候似乎仍无法绕开给子组件加样式的问题。
    比如,我要给一个类似listview中的子组件之间加固定像素的margin,而且第一个子组件之前、最后一个子组件之后无margin,我该怎么做呢?目前我的办法是在它们的父组件上加一个属性gap,然后在这个父组件的定义里遍历children并cloneElement。似乎只有这样才能满足我想要的效果,在父组件上简单加个gap属性就能决定子组件之间的间隔。
    <MyParentComponent gap={3}>
    <MyChildA/>//这个子组件没有margin-top
    <MyChildA/>
    <MyChildB/>
    <MyChildB/>//这个子组件没有margin-bottom
    </MyParentComponent>

    补充一点,上述方法还是需要手动在MyChildA和MyChildB的渲染逻辑里手动继承this.props.style(这个style来源于cloneElement),所以我也在怀疑这是不是理想的解决办法。



  • @nsy1661 建议的做法: 将子组件编写为可以接受style属性(然后和自身的样式进行混合),然后在renderRow里提供辅助的样式。
    组件本身的样式还在组件内部定义。



  • @nsy1661 参见这里的2、3



  • @tdzl2003 谢谢再次回答!您的那篇文章我需要细读并消化一下。。。
    我粗略思考一下,似乎还是没有办法达到我所举的例子(除了父元素gap属性之外无需写其他多余的代码)那样简洁的程度。不过至少思路开阔了不少。


登录后回复