ReactJs: Какими должны быть PropTypes для this.props.children?

265

Учитывая простой компонент, который делает его потомки:

class ContainerComponent extends Component {
  static propTypes = {
    children: PropTypes.object.isRequired,
  }

  render() {
    return (
      <div>
        {this.props.children}
      </div>
    );
  }
}

export default ContainerComponent;

Вопрос: Каким должен быть propType детей prop?

Когда я устанавливаю его как объект, происходит сбой при использовании компонента с несколькими дочерними элементами:

<ContainerComponent>
  <div>1</div>
  <div>2</div>
</ContainerComponent>

Предупреждение: Ошибка типа проп: Invalid опора childrenтипа , array подаваемого ContainerComponent, как ожидается object.

Если я установлю его как массив, произойдет сбой, если я дам ему только один дочерний элемент, т.е.

<ContainerComponent>
  <div>1</div>
</ContainerComponent>

Предупреждение: Ошибка типа проп: недопустимые потомки объекта типа объекта, переданные в ContainerComponent, ожидаемый массив.

Пожалуйста, посоветуйте, не стоит ли мне заняться проверкой propTypes для дочерних элементов?

d3ming
источник
Вы, вероятно, хотитеnode
люкс
1
Возможная
копия разрешить только дочерние элементы
2
Пожалуйста, смотрите мой ответ ниже, который описывает больше опций, но, если вы ищете компонент child, то это PropTypes.element. PropTypes.node описывает все, что может быть визуализировано - строки, числа, элементы или массив этих вещей. Если это вас устраивает, то это путь.
ggilberth

Ответы:

370

Попробуйте что-то вроде этого, используя oneOfTypeилиPropTypes.node

import PropTypes from 'prop-types'

...

static propTypes = {
    children: PropTypes.oneOfType([
        PropTypes.arrayOf(PropTypes.node),
        PropTypes.node
    ]).isRequired
}

или

static propTypes = {
    children: PropTypes.node.isRequired,
}
Александр Старосельский
источник
1
К сожалению, происходит сбой с той же ошибкой в ​​случае с одним дочерним childrenэлементом : «Предупреждение: сбойный тип пропуска: недопустимая опора типа object... ожидается массив».
d3ming
25
Это сработало! Самое простое решение - children: PropTypes.nodeэто сработало в обоих случаях. Спасибо за предложения =)
d3ming
6
Единственное, что могло бы прояснить этот ответ, было бы, если бы вы добавили примечание, похожее на ответ @ggilberth, чтобы объяснить, что React.PropTypes.nodeописывает любой визуализируемый объект.
theotherjim
Нет необходимости в массиве, просто PropTypes.node. Это обрабатывает следующее исправление: ничего, строка, один элемент, несколько элементов, фрагмент, компонент.
Дима Тиснек
38

Для меня это зависит от компонента. Если вы знаете, что вам нужно для заполнения, то вы должны попытаться указать исключительно или несколько типов, используя:

PropTypes.oneOfType 

Однако я в основном нахожу, что с более общими компонентами, которые могут иметь много типов потомков, я счастлив использовать:

PropTypes.any

Если вы хотите сослаться на компонент React, вы будете искать

PropTypes.element

Хотя,

PropTypes.node

описывает все, что может быть визуализировано - строки, числа, элементы или массив этих вещей. Если это вас устраивает, то это путь.

ggilberth
источник
7
Proptypes.anyэто слишком распространенный тип. Эслинт не доволен этим.
Алекс Шварц
20

Документация PropTypes имеет следующее

// Anything that can be rendered: numbers, strings, elements or an array
// (or fragment) containing these types.
optionalNode: PropTypes.node,

Таким образом, вы можете использовать PropTypes.nodeдля проверки объектов или массивов объектов

static propTypes = {
   children: PropTypes.node.isRequired,
}
DC.Azndj
источник
12

Ответы здесь, кажется, не совсем точно проверяют детей. nodeиobject слишком вседозволен, я хотел проверить точный элемент. Вот что я в итоге использовал:

  • использование oneOfType([]) для разрешения одного или множества детей
  • Используйте shapeиarrayOf(shape({})) для одиночного и массива детей соответственно
  • Используйте oneOfдля самого дочернего элемента

В итоге как то так:

import PropTypes from 'prop-types'
import MyComponent from './MyComponent'

children: PropTypes.oneOfType([
  PropTypes.shape({
    type: PropTypes.oneOf([MyComponent]),
  }),
  PropTypes.arrayOf(
    PropTypes.shape({
      type: PropTypes.oneOf([MyComponent]),
    })
  ),
]).isRequired

Эта проблема помогла мне понять это более четко: https://github.com/facebook/react/issues/2979

d3vkit
источник
5

Если вы хотите точно подобрать тип компонента, отметьте это

MenuPrimary.propTypes = {
  children: PropTypes.oneOfType([
    PropTypes.arrayOf(MenuPrimaryItem),
    PropTypes.objectOf(MenuPrimaryItem)
  ])
}

Если вы хотите точно подобрать некоторые типы компонентов, отметьте это

const HeaderTypes = [
  PropTypes.objectOf(MenuPrimary),
  PropTypes.objectOf(UserInfo)
]

Header.propTypes = {
  children: PropTypes.oneOfType([
    PropTypes.arrayOf(PropTypes.oneOfType([...HeaderTypes])),
    ...HeaderTypes
  ])
}
Эндрю Лука
источник
2

Попробуйте пользовательские propTypes:

 const  childrenPropTypeLogic = (props, propName, componentName) => {
          const prop = props[propName];
          return React.Children
                   .toArray(prop)
                   .find(child => child.type !== 'div') && new Error(`${componentName} only accepts "div" elements`);
 };


static propTypes = {

   children : childrenPropTypeLogic

}

скрипка

Абденнур ТУМИ
источник
0

Пример:

import React from 'react';
import PropTypes from 'prop-types';

class MenuItem extends React.Component {
    render() {
        return (
            <li>
                <a href={this.props.href}>{this.props.children}</a>
            </li>
        );
    }
}

MenuItem.defaultProps = {
    href: "/",
    children: "Main page"
};

MenuItem.propTypes = {
    href: PropTypes.string.isRequired,
    children: PropTypes.string.isRequired
};

export default MenuItem;

Рисунок: показывает ошибку в консоли, если ожидаемый тип отличается

Рисунок: показывает ошибку в консоли, если ожидаемый тип отличается

Алексей Бируля
источник