<div> non può apparire come discendente di <p>


112

Lo sto vedendo. Non è un mistero di cosa si lamenta:

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

Sono l'autore di SomeComponente SomeOtherComponent. Ma quest'ultimo utilizza una dipendenza esterna ( ReactTooltipda react-tooltip). Probabilmente non è essenziale che questa sia una dipendenza esterna, ma mi permette di provare l'argomento qui che è "un codice che è fuori dal mio controllo".

Quanto dovrei essere preoccupato per questo avviso, dato che il componente annidato funziona bene (apparentemente)? E come dovrei comunque cambiarlo (a condizione che non voglia reimplementare una dipendenza esterna)? C'è forse un design migliore di cui non sono ancora a conoscenza?

Per completezza, ecco l'implementazione di SomeOtherComponent. Viene eseguito solo il rendering this.props.value, e quando si passa con il mouse: una descrizione comando che dice "Some tooltip message":

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

Grazie.


Risposte:


109

Se questo errore si verifica durante l'utilizzo dell'interfaccia utente materiale <Typography> https://material-ui.com/api/typography/ , puoi facilmente cambiare il <p>in a <span>cambiando il valore componentdell'attributo <Typography>dell'elemento:

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

Secondo i documenti di tipografia:

componente: il componente utilizzato per il nodo radice. Una stringa per utilizzare un elemento DOM o un componente. Per impostazione predefinita, mappa la variante a un buon componente del titolo predefinito.

Quindi la tipografia sta scegliendo <p>come impostazione predefinita ragionevole, che puoi modificare. Può avere effetti collaterali ... ha funzionato per me.


È un peccato in termini di SEO, soprattutto se vuoi che il componente sia un'intestazione (da riconoscere), ma con una variante di qualcosa come h4.
pfeds

Facendo ulteriori tentativi, sembra che tu possa avere un elemento Tipografia radice con variant = "inherit" (cioè a livello di pagina), e poi un componente tipografico secondario = "h1" variante = "h5". Sembra funzionare, ma non sono del tutto sicuro di usare la tipografia nel modo giusto ...
pfeds

5
L'ho usato <Typography component={'div'}>e ora funziona senza avvisi. Grazie mille per avermi messo sulla strada giusta!
JohnK

Avevo bisogno di una tipografia per incapsulare il mio div in modo che il mio testo fosse visualizzato correttamente sulla pagina. Senza di esso come elemento genitore, la mia classe CSS non sembrava registrarsi correttamente, strano vero? Comunque ha funzionato a meraviglia, il css si è registrato e ha rimosso i miei errori, dolcezza!
C.Gadd

2
Questa è una risposta per risparmiare tempo reale
YaakovHatam

74

In base al messaggio di avviso, il componente ReactTooltip restituisce un HTML che potrebbe assomigliare a questo:

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

Secondo questo documento , un <p></p>tag può contenere solo elementi inline. Ciò significa che inserire un <div></div>tag al suo interno dovrebbe essere improprio, poiché il divtag è un elemento di blocco. Una nidificazione impropria potrebbe causare problemi come il rendering di tag aggiuntivi , che possono influire su javascript e css.

Se vuoi eliminare questo avviso, potresti voler personalizzare il componente ReactTooltip o attendere che il creatore corregga questo avviso.


Quindi, sì, ho capito cosa è stato renderizzato, ma diresti che tutti i componenti che rendono a divdovrebbero essere refactoring, sulla possibilità di essere usati in a p? Sembra volare di fronte a quanto divsiano stati molto popolari i messaggi di posta elettronica per il confezionamento arbitrario?
Sander Verhagen

2
Immagino di sì, dato che è nella raccomandazione di w3c. Inoltre, potremmo facilmente sostituire a divcon a spanper evitare questo tipo di avviso ma senza influire sulla logica del codice.
JD Hernandez

1
Se ricevi questo errore quando usi direttamente Material UI <Typography> puoi cambiare il "componente", che descrivo di seguito nella mia risposta. Spero che questo aiuti
zayquan

Prova a usare <span> invece di <div> all'interno del tuo <p> - Questo dovrebbe risolverlo. Mi sono imbattuto in questo errore utilizzando <div> per visualizzare un'immagine la cui origine è specificata da una classe css genitore.
Christopher Stock

18

Se stai cercando dove sta succedendo, in console puoi usare: document.querySelectorAll(" p * div ")


16

Il tuo componente potrebbe essere renderizzato all'interno di un altro componente (come a <Typography> ... </Typography>). Pertanto, caricherà il tuo componente all'interno di un file <p> .. </p>non consentito.

Correzione: rimuovere <Typography>...</Typography>perché viene utilizzato solo per il testo normale all'interno di uno <p>...</p>o qualsiasi altro elemento di testo come i titoli.


4
L'ho usato <Typography component={'div'}>e ora funziona senza avvisi. Grazie mille per avermi messo sulla strada giusta!
JohnK

8

Ho ricevuto questo avviso utilizzando i componenti dell'interfaccia utente del materiale , quindi ho testato component="div"as prop nel codice seguente e tutto è diventato corretto:

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

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

In realtà, questo avviso si verifica perché nell'interfaccia utente del materiale il tag HTML predefinito del Gridcomponente è divtag e il Typographytag HTML predefinito è ptag, quindi ora viene visualizzato l'avviso,

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

In breve, l'interfaccia utente del materiale ha dei bug?
Ero Stefano

1
No caro @EroStefano, è intenzionale che lo sviluppatore segua la regola della gerarchia dei livelli inline e di blocco.
AmerllicA

4

Ho avuto un problema simile e ho inserito il componente in "div" invece di "p" e l'errore è andato via.


4

Questo è un vincolo dei browser. Dovresti usare div o article o qualcosa del genere nel metodo di rendering dell'App perché in questo modo puoi inserire tutto ciò che ti piace al suo interno. I tag di paragrafo sono limitati a contenere solo un set limitato di tag (principalmente tag per la formattazione del testo. Non puoi avere un div all'interno di un paragrafo

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

non è un HTML valido. Secondo le regole di omissione dei tag elencate nelle specifiche, il <p>tag viene automaticamente chiuso dal <div>tag, che lascia il </p>tag senza corrispondenza <p>. Il browser è pienamente autorizzato a tentare di correggerlo aggiungendo un <p>tag aperto dopo <div>:

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

Non puoi inserire un <div>all'interno di <p>e ottenere risultati coerenti da vari browser. Fornisci ai browser HTML valido e si comporteranno meglio.

Puoi inserire <div>un <div>pensiero, quindi se lo sostituisci <p>con <div class="p">e lo stile in modo appropriato, puoi ottenere quello che vuoi.


1
quindi come lo rintracci? gli errori si stanno allineando
ichimaru

2

Se stai usando ReactTooltip, per far scomparire l'avviso, ora puoi aggiungere un oggetto wrappercon un valore di span, come questo:

<ReactTooltip wrapper="span" />

Poiché spanè un elemento inline, non dovrebbe più lamentarsi.


Sei il migliore amico mio, il meglio dei migliori. Ti amo.
AmerllicA

2

L'ho ottenuto utilizzando un componente personalizzato all'interno di una <Card.Text>sezione di un <Card>componente in React. Nessuno dei miei componenti era nei tag p


2

L'avviso viene visualizzato solo perché il codice demo ha:

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 in questo modo ci pensa:

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>
    );
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.