<div> no puede aparecer como descendiente de <p>

112

Estoy viendo esto. No es un misterio de qué se queja:

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

Soy el autor de SomeComponenty SomeOtherComponent. Pero este último está usando una dependencia externa ( ReactTooltipdesde react-tooltip). Probablemente no sea esencial que se trate de una dependencia externa, pero me permite probar aquí el argumento de que es "algún código que está fuera de mi control".

¿Qué tan preocupado debería estar por esta advertencia, dado que el componente anidado está funcionando bien (aparentemente)? ¿Y cómo haría para cambiar esto de todos modos (siempre que no quiera volver a implementar una dependencia externa)? ¿Existe tal vez un diseño mejor que todavía no conozco?

En aras de la integridad, aquí está la implementación de SomeOtherComponent. Simplemente se muestra this.props.value, y cuando se desplaza: una información sobre herramientas que dice "Un mensaje de información sobre herramientas":

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

Gracias.

Sander Verhagen
fuente
1
Problema
Jordan Running

Respuestas:

110

Si este error ocurre mientras se usa Material UI <Typography> https://material-ui.com/api/typography/ , entonces puede cambiar fácilmente <p>a a <span>cambiando el valor del componentatributo del <Typography>elemento:

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

Según los documentos de tipografía:

componente: el componente utilizado para el nodo raíz. O una cadena para usar un elemento DOM o un componente. De forma predeterminada, asigna la variante a un buen componente de título predeterminado.

Por lo tanto, la tipografía está eligiendo <p>como un valor predeterminado sensato, que puede cambiar. Puede venir con efectos secundarios ... funcionó para mí.

Zayquan
fuente
Es desafortunado en términos de SEO, especialmente si desea que el componente sea un encabezado (para ser reconocido), pero con una variante de algo como h4.
pfeds
Al seguir avanzando, parece que puede tener un elemento de tipografía raíz con variant = "heredar" (es decir, a nivel de página), y luego un componente de tipografía secundario = "h1" variant = "h5". Parece que funciona, pero no estoy del todo seguro de que esté usando la tipografía de la manera correcta ...
pfeds
5
Usé <Typography component={'div'}>y ahora funciona sin advertencias. ¡Muchas gracias por ponerme en el camino correcto!
JohnK
Necesitaba una tipografía para encapsular mi div para que mi texto se mostrara correctamente en la página. Sin él como elemento principal, mi clase css no parecía registrarse correctamente, extraño, ¿verdad? Sin embargo, esto funcionó de maravilla, el CSS se registró y eliminó mis errores, ¡dulce!
C.Gadd
2
Esta es una respuesta de ahorro de tiempo real
YaakovHatam
74

Según el mensaje de advertencia, el componente ReactTooltip genera un HTML que podría verse así:

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

Según este documento , una <p></p>etiqueta solo puede contener elementos en línea. Eso significa que poner una <div></div>etiqueta dentro debería ser incorrecto, ya que la divetiqueta es un elemento de bloque. El anidamiento incorrecto puede causar fallas como la representación de etiquetas adicionales , lo que puede afectar su javascript y css.

Si desea deshacerse de esta advertencia, es posible que desee personalizar el componente ReactTooltip o esperar a que el creador corrija esta advertencia.

JD Hernández
fuente
Entonces, sí, entendí lo que se renderizó, pero ¿diría entonces que cualquier componente que renderice a divdebería ser refactorizado, en la posibilidad de ser utilizado en a p? ¿Parece ir en contra de lo populares que divhan sido los s para envolver cosas arbitrariamente?
Sander Verhagen
2
Supongo que sí, ya que está en la recomendación de w3c. Además, podríamos reemplazar fácilmente a divpor a spanpara evitar este tipo de advertencia pero sin afectar nada en la lógica del código.
JD Hernandez
1
Si obtiene este error al usar Material UI <Typography> directamente, puede cambiar el "componente", que describo a continuación en mi respuesta. Espero que esto ayude
zayquan
Intente usar <span> en lugar de <div> dentro de su <p> - Esto debería solucionarlo. Me encontré con este error al usar <div> para mostrar una imagen cuya fuente está especificada por una clase css principal.
Christopher Stock
18

Si está buscando dónde está sucediendo esto, en la consola puede usar: document.querySelectorAll(" p * div ")

Alex C
fuente
16

Su componente puede estar renderizado dentro de otro componente (como a <Typography> ... </Typography>). Por lo tanto, cargará su componente dentro de una <p> .. </p>que no está permitida.

Solución: elimine <Typography>...</Typography>porque esto solo se usa para texto sin formato dentro de uno <p>...</p>o cualquier otro elemento de texto, como encabezados.

Dion Duimel
fuente
4
Usé <Typography component={'div'}>y ahora funciona sin advertencias. ¡Muchas gracias por ponerme en el camino correcto!
JohnK
8

Recibí esta advertencia al usar componentes Material UI , luego component="div"probé como prop en el siguiente código y todo se volvió correcto:

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

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

En realidad, esta advertencia ocurre porque en la interfaz de usuario de Material la etiqueta HTML predeterminada del Gridcomponente es la divetiqueta y la Typographyetiqueta HTML predeterminada es la petiqueta. Así que ahora ocurre la advertencia,

Warning: validateDOMnesting(...): <div> cannot appear as a descendant of <p>
AmerllicA
fuente
En pocas palabras, ¿Material UI tiene errores?
Ero Stefano
1
No querido @EroStefano, esto es intencional que el desarrollador siga la regla de la jerarquía de niveles en línea y de bloque.
AmerllicA
4

Tuve un problema similar y envolví el componente en "div" en lugar de "p" y el error desapareció.

jbluft
fuente
4

Esta es una limitación de los navegadores. Debes usar div o article o algo así en el método de renderizado de la aplicación porque de esa manera puedes poner lo que quieras dentro. Las etiquetas de párrafo están limitadas a contener solo un conjunto limitado de etiquetas (en su mayoría etiquetas para dar formato al texto. No puede tener un div dentro de un párrafo

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

no es HTML válido. Según las reglas de omisión de etiquetas enumeradas en la especificación, la <p>etiqueta se cierra automáticamente por la <div>etiqueta, lo que deja la </p>etiqueta sin una coincidencia <p>. El navegador tiene derecho a intentar corregirlo agregando una <p>etiqueta abierta después de <div>:

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

No puede poner un <div>dentro de un <p>y obtener resultados consistentes de varios navegadores. Proporcione a los navegadores HTML válido y se comportarán mejor.

Se puede poner <div>dentro de una <div>, así que si vas a cambiar de <p>con <div class="p">y estilo de manera apropiada, se puede obtener lo que desea.

jithu
fuente
1
entonces, ¿cómo rastreas esto? los errores se están alineando
ichimaru
2

Si está utilizando ReactTooltip, para hacer desaparecer la advertencia, ahora puede agregar un wrapperaccesorio con un valor de span, como este:

<ReactTooltip wrapper="span" />

Dado que spanes un elemento en línea, ya no debería quejarse.

Nicco
fuente
Eres el mejor amigo mío, el mejor de los mejores. Te amo.
AmerllicA
2

Obtuve esto al usar un componente personalizado dentro de una <Card.Text>sección de un <Card>componente en React. Ninguno de mis componentes estaba en etiquetas p

BitShift
fuente
2

La advertencia aparece solo porque el código de demostración tiene:

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

Cambiarlo así se encarga de ello:

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
fuente