<div> não pode aparecer como descendente de <p>

112

Estou vendo isso. Não é um mistério sobre o que está reclamando:

Warning: validateDOMnesting(...): <div> cannot appear as a descendant of <p>. See ... SomeComponent > p > ... > SomeOtherComponent > ReactTooltip > div.

Eu sou o autor de SomeComponente SomeOtherComponent. Mas o último está usando uma dependência externa ( ReactTooltipde react-tooltip). Provavelmente não é essencial que esta seja uma dependência externa, mas me permite tentar o argumento aqui de que é "algum código que está fora do meu controle".

Devo ficar preocupado com esse aviso, visto que o componente aninhado está funcionando perfeitamente (aparentemente)? E como eu faria para mudar isso de qualquer maneira (desde que eu não queira reimplementar uma dependência externa)? Existe talvez um design melhor que eu ainda não conheça?

Para completar, aqui está a implementação de SomeOtherComponent. Ele apenas renderiza this.props.valuee quando passa o mouse: uma dica de ferramenta que diz "Alguma mensagem de dica de ferramenta":

class SomeOtherComponent extends React.Component {
  constructor(props) {
    super(props)
  }

  render() {
    const {value, ...rest} = this.props;
    return <span className="some-other-component">
      <a href="#" data-tip="Some tooltip message" {...rest}>{value}</a>
      <ReactTooltip />
    </span>
  }
}

Obrigado.

Sander Verhagen
fonte
1
Problema relacionado: github.com/wwayne/react-tooltip/issues/210
Jordan em execução em

Respostas:

109

Se esse erro ocorrer durante o uso de Material UI <Typography> https://material-ui.com/api/typography/ , então você pode facilmente alterar o <p>para um <span>alterando o valor do componentatributo do <Typography>elemento:

<Typography component={'span'} variant={'body2'}>

De acordo com os documentos de tipografia:

componente: o componente usado para o nó raiz. Uma string para usar um elemento DOM ou um componente. Por padrão, ele mapeia a variante para um bom componente de título padrão.

Portanto, a tipografia é escolhida <p>como um padrão sensato, que você pode alterar. Pode vir com efeitos colaterais ... funcionou para mim.

zayquan
fonte
É lamentável em termos de SEO, especialmente se você deseja que o componente seja um cabeçalho (para ser reconhecido), mas com uma variante de algo como h4.
pfeds de
Em mais detalhes, parece que você pode ter um elemento de tipografia raiz com variante = "herdar" (ou seja, no nível da página), e então um componente de sub Tipografia = variante "h1" = "h5". Parece funcionar, mas não tenho certeza se estou usando a tipografia da maneira certa ...
pfeds
5
Usei <Typography component={'div'}>e funciona sem avisos agora. Muito obrigado por me colocar no caminho certo!
JohnK de
Eu precisava de uma tipografia para encapsular meu div de modo que meu texto fosse exibido corretamente na página. Sem ele como um elemento pai, minha classe css não parecia estar registrando corretamente, certo estranho? Porém funcionou como um encanto, o css registrou e removeu meus erros, fofo!
C.Gadd 01 de
2
Esta é uma resposta que economiza tempo real
Yaakov Hatam
74

Com base na mensagem de aviso, o componente ReactTooltip renderiza um HTML que pode ter a seguinte aparência:

<p>
   <div>...</div>
</p>

De acordo com este documento , uma <p></p>tag pode conter apenas elementos embutidos. Isso significa que colocar uma <div></div>tag dentro dela deve ser impróprio, pois a divtag é um elemento de bloco. O aninhamento impróprio pode causar falhas como a renderização de tags extras , o que pode afetar seu javascript e CSS.

Se você deseja se livrar deste aviso, convém personalizar o componente ReactTooltip ou esperar que o criador corrija esse aviso.

JD Hernandez
fonte
Então, sim, entendi o que foi renderizado, mas você diria que quaisquer componentes que renderizam a divdevem ser refatorados, sob a chance de serem usados ​​em a p? Parece desafiar o quão populares os programas divtêm sido para embrulhar coisas arbitrariamente?
Sander Verhagen
2
Acho que sim, já que está na recomendação do w3c. Além disso, poderíamos facilmente substituir a divpor a spanpara evitar esse tipo de aviso, mas sem afetar nada na lógica do código.
JD Hernandez
1
Se você receber este erro ao usar Material UI <Typography> diretamente, você pode alterar o "componente", que descrevo abaixo em minha resposta. Espero que isso ajude
zayquan
Tente usar <span> em vez de <div> dentro do seu <p> - Isso deve corrigir o problema. Encontrei este erro ao usar <div> para exibir uma imagem cuja origem é especificada por uma classe css pai.
Christopher Stock de
18

Se você está procurando onde isso está acontecendo, no console você pode usar: document.querySelectorAll(" p * div ")

Alex C
fonte
16

Seu componente pode ser renderizado dentro de outro componente (como a <Typography> ... </Typography>). Portanto, ele irá carregar seu componente dentro de um <p> .. </p>que não é permitido.

Correção: Remover <Typography>...</Typography>porque isso só é usado para texto simples dentro de um <p>...</p>ou qualquer outro elemento de texto, como títulos.

Dion Duimel
fonte
4
Usei <Typography component={'div'}>e funciona sem avisos agora. Muito obrigado por me colocar no caminho certo!
JohnK de
8

Recebi esse aviso usando componentes de IU de material , testei o component="div"as prop para o código abaixo e tudo ficou correto:

import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';

<Typography component="span">
  <Grid component="span">
    Lorem Ipsum
  </Grid>
</Typography>

Na verdade, esse aviso acontece porque na IU do Material a tag HTML padrão do Gridcomponente é divtag e a Typographytag HTML padrão é ptag, então agora o aviso acontece,

Warning: validateDOMnesting(...): <div> cannot appear as a descendant of <p>
AmerllicA
fonte
Resumindo, a IU do material tem bugs?
Ero Stefano
1
Não caro @EroStefano, é intencional que o desenvolvedor siga a regra da hierarquia de níveis inline e de bloco.
AmerllicA 01 de
4

Tive um problema semelhante e envolvi o componente em "div" em vez de "p" e o erro foi embora.

Jbluft
fonte
4

Esta é uma restrição dos navegadores. Você deve usar div, article ou algo parecido no método de renderização do App, porque dessa forma você pode colocar o que quiser dentro dele. As tags de parágrafo são limitadas a conter apenas um conjunto limitado de tags (principalmente tags para formatação de texto. Você não pode ter uma div dentro de um parágrafo

<p><div></div></p>

não é um HTML válido. De acordo com as regras de omissão de tag listadas na especificação, a <p>tag é fechada automaticamente pela <div>tag, o que a deixa </p>sem correspondência <p>. O navegador está dentro de seus direitos para tentar corrigi-lo adicionando uma <p>tag de abertura após <div>:

<p></p><div></div><p></p>

Você não pode colocar um <div>dentro de um <p>e obter resultados consistentes de vários navegadores. Forneça aos navegadores um HTML válido e eles se comportarão melhor.

Você pode colocar <div>dentro de um <div>pensamento, portanto, se substituir o seu <p>por um <div class="p">estilo adequado, poderá obter o que deseja.

jithu
fonte
1
então, como você rastreia isso? os erros estão se alinhando
ichimaru
2

Se você estiver usando ReactTooltip, para fazer o aviso desaparecer, agora você pode adicionar um wrapperprop com um valor de span, como este:

<ReactTooltip wrapper="span" />

Como spané um elemento embutido, ele não deve mais reclamar.

Nicco
fonte
Você é o melhor, meu amigo, o melhor dos melhores. Vos amo.
AmerllicA
2

Consegui isso usando um componente personalizado dentro de uma <Card.Text>seção de um <Card>componente no React. Nenhum dos meus componentes estava nas tags p

BitShift
fonte
2

O aviso aparece apenas porque o código de demonstração tem:

function TabPanel(props) {
  const { children, value, index, ...other } = props;

  return (
    <div
      role="tabpanel"
      hidden={value !== index}
      id={`simple-tabpanel-${index}`}
      aria-labelledby={`simple-tab-${index}`}
      {...other}
    >
      {value === index && (
        <Box p={3}>  // <==NOTE P TAG HERE
          <Typography>{children}</Typography>
        </Box>
      )}
    </div>
  );
}

Mudá-lo assim resolve:

function TabPanel(props) {
    const {children, value, index, classes, ...other} = props;

    return (
        <div
            role="tabpanel"
            hidden={value !== index}
            id={`simple-tabpanel-${index}`}
            aria-labelledby={`simple-tab-${index}`}
            {...other}
        >
            {value === index && (
                <Container>
                    <Box>   // <== P TAG REMOVED
                        {children}
                    </Box>
                </Container>
            )}
        </div>
    );
}
VikR
fonte