React: Предупреждение для: PropTypes.object.isRequired, если свойство равно `null`

Созданный на 16 февр. 2015  ·  37Комментарии  ·  Источник: facebook/react

Поскольку PropTypes относится к «типу» опоры, null - это пустой объект, но практически все же тип объекта.

Но все же предупреждает:

 Warning: Required prop `profile` was not specified in `Element`. Check the render method of `OtherElement`.

Я не думаю, что это должно произойти.

Он перестает предупреждать после того, как больше не null . Я почти уверен, что он должен предупреждать только тогда, когда это undefined ?

Самый полезный комментарий

Типичный вариант использования, который я вижу, - это отрисовка компонента в React до завершения вызова API для данных. Первый рендеринг будет отображать, например, список элементов ( items: null ). Затем вызов API завершается, и теперь items заполняется массивом.

Все 37 Комментарий

null эквивалентно отсутствию значения и не является объектом (пустым или каким-либо другим образом). Если вы не хотите, чтобы он предупреждал о null , не делайте этого обязательным, он имеет тот же эффект. Я бы не рекомендовал проверять наличие ключа.

Я согласен. Я не могу вспомнить очень много случаев использования, когда вы хотели бы заставить пользователя указать значение, но были бы готовы принять null как допустимое значение. Для практических целей предупреждение isRequired для null является разумным и ожидаемым поведением.

связанные: https://github.com/facebook/react/issues/2166
(эта проблема по-прежнему заметно отображается в результатах поиска)

Типичный вариант использования, который я вижу, - это отрисовка компонента в React до завершения вызова API для данных. Первый рендеринг будет отображать, например, список элементов ( items: null ). Затем вызов API завершается, и теперь items заполняется массивом.

Я пытаюсь сделать PropTypes.oneOfType([null, PropTypes.object]).isRequired , поэтому либо значение null, либо объект, это невозможно прямо сейчас?

Согласно CHANGELOG , поскольку 15.4.0 предположительно возможно

На самом деле в 15.4.0 все наоборот: Required PropTypes now fail with specific messages for null and undefined.

Я тоже столкнулся с этой проблемой.
Обходной путь
Failed prop type: The prop значение is marked as required in Выбрать , but its value is null .

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

+1 за то, что каким-то образом разрешил null .

У нас есть вариант использования, когда наша конфигурация загружается через JSON, и есть несколько параметров конфигурации меток, которые определяют строку, которая должна отображаться, примерно так:

{
  "title": "my title"
}

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

{
  "title": null
}

(Добавление параллельного hasTitle: false было бы недопустимым, поскольку у нас есть десятки таких настроек.)

Для содержимого JSON использование null - очень полезный способ отличить неопределенное ( undefined ) от намеренно пропущенного ( null ).

вы можете разрешить null, установить propType как необязательный, поскольку он не требуется: P

@jquense, спасибо, это очень полезно! Я удалил свой предыдущий комментарий, потому что в этом SO- ответе говорилось то же самое.

@jquense вы можете разрешить null AND undefined, но не одно или другое.

Вот и вся проблема! Javascript предоставил эти две разные конструкции по какой-то причине, поэтому принуждение всех обрабатывать null === undefined для PropTypes является искусственным ограничением.

То, что я хочу, чтобы PropType явно разрешал null, не означает, что мне также нужно разрешить undefined. Это два разных случая, и язык специально разработал их таким образом.

У меня есть PR, чтобы обойти эту оплошность здесь: https://github.com/facebook/prop-types/pull/90

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

@binki Один из способов разрешить null но не undefined - использовать вашу собственную функцию валидатора PropType.

В приведенном ниже примере разрешены только null или string . Библиотека PropTypes использует typeof внутри для проверки строк, поэтому я сделал то же самое. Одним из преимуществ является то, что вы можете переместить эту функцию за пределы вашего компонента и вызывать ее по мере необходимости.

static propTypes = {
  id: PropTypes.number.isRequired,
  email: function(props, propName, componentName) {
    const propValue = props[propName] // the actual value of `email` prop
    if (propValue === null) return
    if (typeof propValue === 'string') return
    return new Error(`${componentName} only accepts null or string`)
  }
}

Я предполагаю, что это решение отклоняется от цели библиотеки PropTypes - я говорю, что это связано с приведенным ниже кодом из библиотеки PropTypes по адресу https://github.com/facebook/prop-types/blob/master/factoryWithTypeCheckers.js # L189.

Перед фактической проверкой выполняется быстрая проверка, при которой свойства, установленные с помощью isRequired, автоматически выдают ошибку, если значение свойства равно null . Другими словами, они считают, что обязательное свойство, имеющее значение NULL, ошибочно, тогда как я считаю допустимым вариантом использования наличие требуемых значений NULL.

if (props[propName] == null) {
  if (isRequired) {
    if (props[propName] === null) {
      return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required ' + ('in `' + componentName + '`, but its value is `null`.'));
    }
    return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required in ' + ('`' + componentName + '`, but its value is `undefined`.'));
  }
  return null;
} else {
  return validate(props, propName, componentName, location, propFullName);
}

Я согласен с @ jharris4 по указанным причинам. null - это не то же самое, что undefined . Стандартно использовать его как заполнитель.

Из сети разработчиков Mozilla:

Значение null представляет собой преднамеренное отсутствие какого-либо значения объекта.

null не является идентификатором свойства глобального объекта, в отличие от undefined. Вместо этого null означает отсутствие идентификации, указывая на то, что переменная не указывает ни на один объект. В API-интерфейсах значение null часто извлекается в том месте, где можно ожидать объект, но ни один объект не является релевантным.

null должен быть разрешен, по крайней мере, через PropTypes.oneOfType([null, PropTypes.string]).isRequired .

@jquense - Удаление isRequired означает, что вам, вероятно, следует установить значение по умолчанию. Означает ли это, что теперь вы устанавливаете значение по умолчанию для начального значения в компоненте _и_ в редукторе, чтобы не допустить использования null в качестве значения для опоры?

У меня есть куча data || '' ( isRequired принимает пустую строку '' , пустой объект {} и т. Д.) В моих селекторах вызывают при ожидании вызовов API для finish null - идеальная вещь, чтобы сообщить компоненту, что данные поступают, просто подождите немного! (но я не могу этого сделать ...)
У @ puiu91 пока есть хорошая работа ... Я сделаю служебную функцию для использования во всей нашей кодовой базе ... поскольку похоже, что эта проблема не будет повторно открыта в ближайшее время вздох

Я также согласен, что должен существовать стандартный способ принять null в качестве значения по тем же причинам, что и @ jharris4 и @Findiglay , но это не место для продолжения обсуждения. Эта проблема не только закрыта, но и относится к facebook / prop-types . Я слежу за запросом на перенос здесь facebook / prop-types # 90.

Удар. Все еще сталкиваюсь с этим сегодня. Было бы здорово иметь встроенную поддержку для чего-то вроде:

myObj: PropType.object.isRequiredOrNull :)

Я думаю, что приоритет здесь очень низкий. Flow - это рекомендуемый путь. http://flow.org/

@Marujah, ваш фрагмент

Попробуйте передать компоненту null, и вы увидите предупреждение:

Warning: Failed prop type: The prop 'theProp' is marked as required in 'TheComponent', but its value is null.

Дело в том, что isRequired оценивается ПЕРВЫМ и никогда не пропускает нулевые или неопределенные значения.

Связь с PR-типами для решения проблемы приведена выше, если вам интересно.

Ой, действительно! перепроверил еще раз, ты прав

Требование, чтобы значение или ноль были указаны специально, должно быть абсолютно разрешено через PropTypes.

Вот пример использования, с которым я столкнулся. У нас есть обратные вызовы, которые требуются 90% наших селекторов. Те немногие, кому они не нужны, представляют собой очень специфические варианты использования. У нас есть несколько новых разработчиков, которые постоянно забывают предоставить все обычные обратные вызовы.

Я хочу, чтобы все пользователи этих компонентов принимали осознанное решение не включать конкретные обратные вызовы, а не просто забывать некоторые реквизиты.

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

Просто хотел добавить сюда свой вариант использования. У меня есть хранилище redux с данными вместе с тем, когда эти данные были извлечены, если произошла ошибка и т. Д. Моему компоненту требуется опора 'error' (чтобы он мог отображать ошибку пользователю, если данные не могут быть извлечены), который имеет значение NULL при успешной загрузке данных, но заполняется при возникновении ошибки.

Я передаю компонент загрузчика ( PropTypes.node ) как props , а когда я не хочу отображать загрузчик, я передаю null .
Afaik, функция render должна возвращать null вместо undefined когда ничего не отрисовывается. Итак, передача null в качестве значения выглядит для меня правильным способом.

Я реализовывал компонент InputNumber (оболочка для <input type="number"> ), поэтому у меня был propTypes для моей опоры value - PropTypes.number.isRequired , и когда я использовал свой компонент, я всегда передавал это свойство. Но сегодня мне нужно передать туда ссылку на значение по умолчанию, допускающую значение NULL, и мой компонент добавляет предупреждение. Единственное решение, которое я мог себе представить, - это изменить propTypes для моей опоры value на PropTypes.oneOfType([PropTypes.number, PropTypes.string]) и установить defaultProps как null. Но я считаю, что это неправильный вариант, потому что input type = number должен работать только с числами.

Я пытаюсь сделать PropTypes.oneOfType([null, PropTypes.object]).isRequired , поэтому либо значение null, либо объект, это невозможно прямо сейчас?

Ожидается функция: Warning: Invalid argument supplied to oneOfType. Expected an array of check functions, but received null at index 1.

Итак, вы должны предоставить функцию, например:

PropTypes.oneOfType([
  () => null,
  PropTypes.object
]).isRequired

Только что столкнувшись с этой ошибкой, я написал удобную функцию, чтобы ее обойти:

function nullable(subRequirement) {
  const check = (required, props, key, ...rest) => {
    if (props[key] === null) {
      return null;
    }
    const sub = required ? subRequirement.isRequired : subRequirement;
    return sub(props, key, ...rest);
  };
  const fn = check.bind(null, false);
  fn.isRequired = check.bind(null, true);
  return fn;
}

Использование:

static propTypes = {
  someCallbackFunction: nullable(PropTypes.func).isRequired,
};

Возможно (но бессмысленно) использовать nullable без isRequired . Причина, по которой я делаю его совместимым с isRequired заключается в том, что он будет работать с правилом react/require-default-props eslint.

Мой вариант использования - это серия компонентов, соответствующих общему API, заключенных в один компонент, который обрабатывает обратные вызовы. null callbacks означают "только чтение", поэтому компонент-оболочка иногда намеренно передает null s. В то же время важно, чтобы каждое свойство передавалось подкомпонентам, чтобы гарантировать, что при добавлении нового свойства оно не будет пропущено. Я также не хочу предоставлять defaultProps null для каждого компонента, который соответствует этому API; насколько им известно, вызывающий должен указать значение.

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

npm install --save git+https://github.com/davidje13/prop-types-nullable.git#semver:^1.0.0

Использование:

import PropTypes from 'prop-types';
import nullable from 'prop-types-nullable';

[...]

static propTypes = {
  thing: nullable(PropTypes.string).isRequired,
};

Новое решение: PropTypes.oneOfType([PropTypes.object]).isRequired

Я получаю сообщение об ошибке.
как исправить.

ПРЕДУПРЕЖДЕНИЕ в ./~/prop-types/prop-types.js Критические зависимости: 1: 482-489 Похоже, это предварительно созданный файл javascript. Хотя это возможно, это не рекомендуется. Для получения лучших результатов попробуйте запросить первоисточник. @ ./~/prop-types/prop-types.js 1: 482-489

Я пытаюсь сделать PropTypes.oneOfType([null, PropTypes.object]).isRequired , поэтому либо значение null, либо объект, это невозможно прямо сейчас?

Ожидается функция: Warning: Invalid argument supplied to oneOfType. Expected an array of check functions, but received null at index 1.

Итак, вы должны предоставить функцию, например:

PropTypes.oneOfType([
  () => null,
  PropTypes.object
]).isRequired

На самом деле у меня была ошибка из-за того, что в конце isRequired, будучи нулевым и требуемым, в то же время несовместимо ...
Вот что сработало для меня:

PropTypes.oneOfType([ 
    PropTypes.string.isRequired, 
    () => null 
])

@ gugol2 обратите внимание, что то, что вы написали, просто полностью отключит проверку типов (теперь вы можете передать число в эту опору, или undefined , или что-то еще); предоставляемая вами функция должна возвращать null если проверка прошла успешно, и не null случае неудачи.

Если вы хотите пойти по этому пути, вам понадобится что-то вроде:

PropTypes.oneOfType([
  PropTypes.string.isRequired,
  (props, key) => props[key] === null ? null : 'Not null'
])

Конечно, вы можете заранее определить отвратительно выглядящую вспомогательную функцию:

const nullable = (props, key) => props[key] === null ? null : 'Not null'

// ...

PropTypes.oneOfType([PropTypes.string.isRequired, nullable])

Также странно возможно (но я бы действительно не рекомендовал!) Просто использовать PropTypes.oneOfType([PropTypes.string.isRequired]) . Это похоже на ошибку, и я не ожидал, что такой код выживет в более поздних версиях. Также обратите внимание, что он похож, но не совпадает с ранее предложенным методом, который не работает.


Если вы можете подождать, есть открытый PR, который продвигается невероятно медленно, но, по-видимому, все еще рассматривается.

И до тех пор, пока PR не будет объединен, я бы рекомендовал использовать созданный мной пакет (или код, стоящий за ним ), потому что таким образом вы можете поставить .isRequired в конце строки, что делает его совместимым с правилами линтинга.

ИМХО, это правильное поведение, но оно должно быть задокументировано.

Типичный вариант использования, который я вижу, - это отрисовка компонента в React до завершения вызова API для данных. Первый рендеринг будет отображать, например, список элементов ( items: null ). Затем вызов API завершается, и теперь items заполняется массивом.

Как лучше с этим справиться? Я хочу, чтобы эта опора обязательна, НО она равна нулю, прежде чем я верну ее из API.

PropTypes.oneOfType([
  PropTypes.string.isRequired,
  (props, key) => props[key] === null ? null : 'Not null'
])

@ davidje13 У меня возникла небольшая проблема с этим подходом. При тестировании покрытия 1/4 случая никогда не покрывается.

Скажем, у меня есть компонент Login, который имеет только одно свойство 'name', которое может быть нулевым или обязательной строкой:

const Login = ({name}) => {
  return <div>{name}</div>
} 

Итак, его проптипы:

Login.propTypes = {
  name: PropTypes.oneOfType([
    PropTypes.string.isRequired,
    (props, key) => (props[key] === null ? null : 'Not null'),
  ]),
};

Когда я тестирую этот компонент, у меня действительно есть только два сценария: null ИЛИ требуемая строка.

render(<Login name={null} />
render(<Login name={'anyName'} />

Но покрытие говорит мне, что мой тест охватывает только 75%.
Интересно, каков будет официальный подход к этому.

Похоже, ваш отсутствующий тестовый пример - это тот, где он не проходит проверку опоры? т.е. если вы передаете число или undefined, или что-то еще, чего не должно быть.

Похоже, ваш отсутствующий тестовый пример - это тот, где он не проходит проверку опоры? т.е. если вы передаете число или undefined, или что-то еще, чего не должно быть.

Нет, не то.

Передача undefined не расширяет охват.
И я все равно не могу передать число, это недопустимое значение.

Я не могу раскрыть этот случай.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги