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 для дочерних элементов?


Вы, вероятно, хотитеnode
— люкс


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

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


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,
}

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


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;

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.