Разметка дочерних компонентов с использованием ReactNative и StyledComponents - PullRequest
0 голосов
/ 06 июня 2019

Я пытаюсь применить макет для набора дочерних элементов в контексте ReactNative и StyledComponents .Моя конкретная проблема заключается в том, что мне нужно добавить поля для всех, кроме последнего из набора дочерних элементов, чтобы контролировать расстояние между элементами flex (все контейнеры display: flex в ReactNative).Я не хочу добавлять поля bottom к самим компонентам, так как думаю, что это может выйти из-под контроля, так как компоненты должны быть повторно использованы во многих местах.

Я пробовал много разныхспособы нацеливания на детей в StyledComponents, и ни один из них не имеет никакого эффекта:

  • > *
  • & > *
  • .some-class (className амортизируется в ReactNativeView s)

Мое лучшее текущее решение заключается в том, чтобы обернуть наборы дочерних элементов в определенные объекты обработки Layout, но это просто переместило ответственность на другого дочернего элемента, когда я чувствую, что это в основном интуитивно решаетсяparent (который также соответствует фундаментальному принципу спецификаций макета flex и grid).

Мне интересно узнать, как эта проблема была решена другими, чтобы я мог сделать это наилучшим образомвозможно.

Вот разметка, которую я пытаюсь разметить:

<View>
  <Could />
  <Be />
  <Anything />
  <Valid />
</View>

Что будет отображаться как - каждый элемент имеет одинаковое поле, а последний элемент не имеет:

enter image description here

И вот как я бы сделал это в ванильном CSS с flex:

.laid-out {
  display: flex;
  flex-direction: column;
}

.laid-out > * {
  margin-bottom: 10px;  
}

.laid-out > *:last-child {
  margin-bottom: 0;
}

Какое решение является лучшим здесь

1 Ответ

0 голосов
/ 06 июня 2019

Вы подняли некоторые хорошие моменты и замечания - особенно в отношении использования flex-свойств родителя для размещения дочерних элементов с пробелом, вместо того, чтобы делегировать макет дочернему элементу родителя для переноса и добавления поля.

Я подготовил закуску, в которой описывается обе реализации: https://snack.expo.io/HyXElYL0V

Первый вариант: обернуть каждого ребенка и добавить поле: (GapLayout.js)

Здесь мы просто обертываем каждый дочерний объект объектом View и добавляем к нему любой отступ / отступ, за исключением последнего дочернего элемента, если это необходимо.

const GapLayout = ({ children }) => (
  <View style={Styles.layoutContainer}>
    {children.map((child, index) => {
      const isLastChild = children.length === index + 1

      return (
        <View style={[Styles.layoutItemWrapper, { marginBottom: isLastChild ? 0 : 8 }]}>
          {child}
        </View>
      )
    })}
  </View>
)

Это позволяет наценку, описанную вами выше:

<GapLayout>
  <WideContent />
  <WideContent />
  <WideContent />
</GapLayout>

Второй вариант: установите соответствующую родительскую высоту так, чтобы justifyContent: 'space -ween' works (GapLayout2.js)

Было бы супер идеальным просто использовать {justifyContent: 'space -ween'} на родительском объекте, и это работает волшебно.Однако для создания пространства между элементами родитель должен быть выше, чем все дочерние элементы.

Поскольку мы добавляем несколько дочерних элементов неизвестной длины, нам нужно, чтобы родительский элемент имел высоту: неизвестная длина+ (количество детей - 1) * margin

class GapLayout2 extends React.Component {
  constructor() {
    super();

    this.state = {
      contentHeight: null,
    };
  }

  setContentHeight = e => {
    const { contentHeight } = this.state
    const { children, itemMargin } = this.props

    // Return if we already set a contentHeight to prevent an infinite-render-loop.
    if(contentHeight) return

    this.setState({
      contentHeight: e.nativeEvent.layout.height + (children.length - 1) * itemMargin
    })
  }

  render() {
    const { children } = this.props;
    const {contentHeight} = this.state

    return (
      <View onLayout={this.setContentHeight} style={[Styles.layoutContainer, contentHeight && { height: contentHeight }]}>
        {children}
      </View>
    );
  }
}

Что здесь происходит:

  1. Мы отображаем родительский элемент и все его содержимое.
  2. Мы используемобратный вызов onLayout для получения content-height.
  3. В setContentHeight мы затем устанавливаем setState с новым ContentHeight + margin.
  4. Как только у нас будет contentHeight, мы затем визуализируем родительский объектс новой высотой:

    style = {[Styles.layoutContainer, contentHeight && {height: contentHeight}]}

Это позволяет намта же наценка, без упаковки детей.И я полагаю, что это позволит прямым детям использовать flex: 1/2/10 друг с другом, поскольку все они имеют одного и того же родителя (тогда как если бы они были обернуты, это не сработало бы).

Будетлюблю видеть другие идеи и реализации.

Ура,

...