React: Aviso para: PropTypes.object.isRequired quando prop é `null`

Criado em 16 fev. 2015  ·  37Comentários  ·  Fonte: facebook/react

Como PropTypes é sobre o 'tipo' de objeto, null é um objeto vazio, mas ainda é um tipo de objeto, praticamente.

Mas ainda assim avisa:

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

Eu não acho que isso deveria acontecer.

Ele para de alertar depois que não for mais null . Tenho certeza que ele só deve avisar quando for undefined ?

Comentários muito úteis

Um caso de uso comum que vejo é o React renderizando um componente antes que uma chamada de API para dados seja concluída. A primeira renderização renderia, por exemplo, uma lista de itens ( items: null ). Em seguida, a chamada API termina e agora items é preenchido com uma matriz.

Todos 37 comentários

null é o equivalente a nenhum valor e não é um objeto (vazio ou não). Se você não quiser que ele avise por null então não o torne obrigatório, ele tem o mesmo efeito. Testar a presença de uma chave não é algo que eu recomendaria.

Eu concordo. Não consigo pensar em muitos casos de uso em que você desejaria forçar um usuário a especificar um valor, mas estaria disposto a aceitar null como um valor válido. Para fins práticos, o aviso isRequired para nulo é um comportamento sensato e esperado.

relacionado: https://github.com/facebook/react/issues/2166
(este problema ainda aparece com destaque nos resultados da pesquisa)

Um caso de uso comum que vejo é o React renderizando um componente antes que uma chamada de API para dados seja concluída. A primeira renderização renderia, por exemplo, uma lista de itens ( items: null ). Em seguida, a chamada API termina e agora items é preenchido com uma matriz.

Estou tentando fazer PropTypes.oneOfType([null, PropTypes.object]).isRequired , então nulo ou um objeto, isso não é possível agora?

De acordo com o CHANGELOG , uma vez que 15.4.0 é suposto ser possível

Na verdade, é o oposto em 15.4.0: Required PropTypes now fail with specific messages for null and undefined.

Eu também estou enfrentando esse problema.
A solução alternativa de @Noitidart não está funcionando para mim. Ele lança um erro dizendo:
Failed prop type: The prop value is marked as required in Selecione , but its value is null .

Acho muito útil exigir uma propriedade, mas também permitir valores nulos.

1 por permitir null alguma forma.

Temos um caso de uso em que nossa configuração é carregada via JSON e existem várias opções de configuração de rótulo que especificam uma string que deve ser exibida, algo como isto:

{
  "title": "my title"
}

Portanto, quando nenhum título deve ser exibido, usamos null para denotar esse caso:

{
  "title": null
}

(Adicionar hasTitle: false paralelo seria proibitivo, pois temos dezenas dessas configurações.)

Para conteúdo JSON, usar null é uma maneira muito útil de distinguir entre não definido ( undefined ) e deliberadamente omitido ( null ).

você pode permitir null, defina o propType para não ser obrigatório, uma vez que não é obrigatório: P

@jquense obrigado, isso é super útil! Excluí meu comentário anterior porque essa resposta do SO disse a mesma coisa.

@jquense você pode permitir nulo E indefinido, mas não um ou outro.

Esse é todo o problema! Javascript forneceu essas 2 construções diferentes por uma razão, então forçar todos a tratar null === undefined para PropTypes é uma limitação artificial.

Só porque eu quero que um PropType permita explicitamente nulo, não significa que eu deva permitir undefined também. São dois casos distintos, e a linguagem os projetou dessa forma propositalmente.

Tenho um PR para contornar esse descuido aqui: https://github.com/facebook/prop-types/pull/90

Eu quero desautorizar undefined porque isso significa que há um erro de digitação e permitir null porque isso significa que o chamador passou explicitamente null . Esse é o ponto desta questão. Eu entendo que este problema está resolvido porque é recomendado apenas alternar para o fluxo, que analisarei.

@binki Uma maneira de permitir null mas não undefined é usar sua própria função validadora do PropType.

No exemplo abaixo, apenas null ou string são permitidos. A biblioteca PropTypes usa typeof internamente para verificar se há strings, então fiz o mesmo. Um benefício é que você pode mover essa função para fora do componente e chamá-la quando necessário.

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`)
  }
}

Acho que esta solução se desvia da intenção da biblioteca PropTypes - o motivo pelo qual digo isso é devido ao código abaixo da biblioteca PropTypes em https://github.com/facebook/prop-types/blob/master/factoryWithTypeCheckers.js # L189.

Antes de realmente validar, uma verificação rápida é realizada em que as propriedades definidas com isRequired geram automaticamente um erro se o valor da propriedade for null . Em outras palavras, eles acreditam que uma propriedade obrigatória sendo nula é errônea, enquanto eu considero um caso de uso válido ter valores nulos obrigatórios.

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);
}

Eu concordo com @ jharris4 pelas razões apresentadas. null não é o mesmo que undefined . É padrão usá-lo como um espaço reservado.

Da Mozilla Developer Network:

O valor null representa a ausência intencional de qualquer valor de objeto.

null não é um identificador para uma propriedade do objeto global, como pode ser undefined. Em vez disso, null expressa uma falta de identificação, indicando que uma variável não aponta para nenhum objeto. Em APIs, null é geralmente recuperado em um local onde um objeto pode ser esperado, mas nenhum objeto é relevante.

nulo deve ser permitido, pelo menos até PropTypes.oneOfType([null, PropTypes.string]).isRequired .

@jquense - Remover isRequired significa que você provavelmente deve definir um padrão. Isso significa que você agora configuraria um padrão para o valor inicial no componente _and_ no redutor, tudo para evitar permitir null como um valor para um prop?

Eu tenho um monte de data || '' ( isRequired aceita string vazia '' , objeto vazio {} , etc.) em meus seletores porque enquanto aguardo chamadas de API para terminar null é a coisa perfeita para dizer ao componente que os dados estão chegando, apenas espere um pouco! (mas eu não posso fazer isso ...)
@ puiu91 tem uma boa suspiro

Também concordo que deve haver uma maneira padrão de aceitar null como valor, pelos mesmos motivos que @ jharris4 e @Findiglay declararam, mas este não é o lugar para continuar a discussão. Este problema não foi apenas encerrado, mas também pertence aos tipos de suporte / facebook . Estou seguindo a solicitação de pull aqui facebook / prop-types # 90.

Ressalto. Ainda estou correndo para isso hoje. Seria ótimo ter suporte integrado para algo como:

myObj: PropType.object.isRequiredOrNull :)

Acho que a prioridade nisso é muito baixa. O fluxo é o caminho recomendado para ir. http://flow.org/

@Marujah seu snippet não está correto.

Tente passar null para o componente e você verá o aviso:

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

O problema é que o isRequired é avaliado PRIMEIRO e nunca permitirá a passagem de valores nulos ou indefinidos.

O PR para os tipos de acessórios para corrigir o problema está no link acima, se você estiver interessado.

Oh, de fato! retestei novamente você está certo

Exigir que um valor ou nulo seja fornecido especificamente deve ser absolutamente permitido por meio de PropTypes.

Aqui está o caso de uso que estou encontrando. Temos alguns retornos de chamada exigidos por 90% de nossos seletores. Os poucos que não precisam deles são casos de uso muito específicos. Temos alguns novos desenvolvedores que estão constantemente se esquecendo de fornecer todos os retornos de chamada usuais.

Eu quero forçar todos os usos desses componentes para tomar a decisão consciente de não incluir callbacks específicos, ao invés de alguém simplesmente esquecer alguns adereços.

Sim, podemos hackear nossas próprias verificações mais específicas por meio do fluxo, mas isso divide nossa validação de props em dois lugares e não é intuitivo para alguém olhando para as definições de propTypes.

Só queria adicionar meu caso de uso aqui. Eu tenho um redux store com dados junto com quando os dados foram buscados, se houve um erro, etc. Meu componente requer um prop 'erro' (para que ele possa exibir o erro para o usuário se os dados não puderem ser buscados), que é nulo quando os dados são carregados com êxito, mas preenchido quando há um erro.

Estou passando um componente do carregador ( PropTypes.node ) como props , e quando não quero renderizar um carregador, passo null .
Afaik, uma função render deve retornar null vez de undefined quando não renderizar nada. Portanto, passar null como o valor parece a maneira correta de fazer isso para mim.

Eu estava implementando o componente InputNumber (wrapper para <input type="number"> ), então eu tinha propTypes para meu prop value - PropTypes.number.isRequired , e quando usei meu componente, sempre passou de propriedade. Mas hoje eu preciso passar para lá um link anulável por padrão para valor, e meu componente adiciona um aviso. A única decisão que eu poderia imaginar é mudar propTypes para minha prop value para PropTypes.oneOfType([PropTypes.number, PropTypes.string]) e definir defaultProps como nulo. Mas eu sinto que não é o correto porque o tipo de entrada = número deve funcionar apenas com números.

Estou tentando fazer PropTypes.oneOfType([null, PropTypes.object]).isRequired , então nulo ou um objeto, isso não é possível agora?

Ele espera uma função: Warning: Invalid argument supplied to oneOfType. Expected an array of check functions, but received null at index 1.

Portanto, você deve fornecer uma função, como:

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

Tendo acabado de encontrar esse bug, escrevi uma função de conveniência para contorná-lo:

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

Uso:

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

É possível (mas sem sentido) usar nullable sem isRequired . A razão de eu torná-lo compatível com isRequired é para que funcione com a regra react/require-default-props eslint.

Meu caso de uso é uma série de componentes em conformidade com uma API comum, envolvida por um único componente que lida com retornos de chamada. null callbacks significam 'somente leitura', então o componente wrapper às vezes passa intencionalmente null s. Ao mesmo tempo, é importante que cada propriedade seja passada para os subcomponentes para garantir que, se uma nova propriedade for adicionada, ela não será perdida. Eu também não quero fornecer defaultProps null para cada componente que está em conformidade com esta API; até onde eles sabem, o chamador deve ter especificado um valor.

Peguei o auxiliar que escrevi antes e coloquei em um pacote junto com um monte de testes para provar a correção:

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

Uso:

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

[...]

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

Nova solução: PropTypes.oneOfType([PropTypes.object]).isRequired

Estou recebendo um erro.
como consertar.

AVISO em ./~/prop-types/prop-types.js Dependências críticas: 1: 482-489 Este parece ser um arquivo javascript pré-compilado. Embora isso seja possível, não é recomendado. Tente exigir a fonte original para obter melhores resultados. @ ./~/prop-types/prop-types.js 1: 482-489

Estou tentando fazer PropTypes.oneOfType([null, PropTypes.object]).isRequired , então nulo ou um objeto, isso não é possível agora?

Ele espera uma função: Warning: Invalid argument supplied to oneOfType. Expected an array of check functions, but received null at index 1.

Portanto, você deve fornecer uma função, como:

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

Na verdade eu tive um erro por causa desse 'isRequired' no final, ser nulo e obrigatório ao mesmo tempo não é compatível ...
Isto é o que funcionou para mim:

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

@ gugol2 observe que o que você escreveu apenas desabilitará completamente a verificação de tipo (agora você pode passar um número para esse prop, ou undefined , ou qualquer coisa); a função que você fornece deve retornar null se a validação for bem-sucedida e não null se falhar.

Se você deseja seguir esse caminho, você precisa de algo mais como:

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

Claro que você pode predefinir a função auxiliar de aparência desagradável:

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

// ...

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

Também é estranhamente possível (mas eu realmente não recomendo!) Usar apenas PropTypes.oneOfType([PropTypes.string.isRequired]) . Isso parece um bug e eu não esperaria que um código como esse sobrevivesse às versões posteriores. Observe também que é semelhante, mas não igual, a um método sugerido anteriormente que não funciona.


Se você puder esperar, há um PR aberto que está se movendo incrivelmente devagar, mas aparentemente ainda está em consideração.

E até que o PR seja mesclado, eu recomendo usar o pacote que criei (ou o código por trás dele ) porque dessa forma você coloca .isRequired no final da linha, o que o torna compatível com as regras de linting.

IMHO este é um comportamento correto, mas deve ser documentado.

Um caso de uso comum que vejo é o React renderizando um componente antes que uma chamada de API para dados seja concluída. A primeira renderização renderia, por exemplo, uma lista de itens ( items: null ). Em seguida, a chamada API termina e agora items é preenchido com uma matriz.

Alguma melhor maneira de lidar com isso? Eu quero que esse suporte seja obrigatório, MAS ele é nulo antes de eu recuperá-lo da API.

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

@ davidje13 Eu encontro um pequeno problema com essa abordagem. O teste de cobertura tem 1/4 de caso que nunca é coberto.

Digamos que eu tenha um Login de componente que tem apenas um 'nome' de prop que pode ser nulo ou uma string necessária:

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

Portanto, seus proptypes são:

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

Quando eu testo este componente, eu realmente tenho apenas 2 cenários, null OU uma string necessária.

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

Mas a cobertura me diz que meu teste tem apenas 75% de cobertura.
Eu me pergunto qual será a abordagem oficial para isso.

Parece que seu caso de teste ausente é aquele em que falha na verificação de suporte? ou seja, se você passar um número ou indefinido ou outra coisa que não deveria.

Parece que seu caso de teste ausente é aquele em que falha na verificação de suporte? ou seja, se você passar um número ou indefinido ou outra coisa que não deveria.

Não, não é isso.

Passar por indefinido não expande a cobertura.
E não posso passar um número de qualquer maneira, não é um valor permitido.

Não sou capaz de cobrir esse caso.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

trusktr picture trusktr  ·  3Comentários

jimfb picture jimfb  ·  3Comentários

varghesep picture varghesep  ·  3Comentários

hnordt picture hnordt  ·  3Comentários

huxiaoqi567 picture huxiaoqi567  ·  3Comentários