Błąd "alnchorEl prop provided to the component is invalid"

0

Dzień dobry, podczas debugowania aplikacji webowej wyświetla mi się poniższy problem:

MUI: The `anchorEl` prop provided to the component is invalid.
The anchor element should be part of the document layout.
Make sure the element is present in the document or that it's not display none. 

A oto kod gdzie występuje element anchorEl:

import Popover from "@mui/material/Popover";
....
  const [podpowiedzimie, setpodpowiedzimie] = React.useState(null);
...
  const PokazPodpowiedzImie = (event) => {
    setpodpowiedzimie(event.target);
  };

  ....
      <span style={{ display: "flex", alignItems: "center" }}>
        <TextField
          requireds="true"
          id="outlined-required"
          label="Imię"

          value={imie}
          onChange={Przypisz_Imie}
          error={!!tekst_bledu_imie}
          helperText={tekst_bledu_imie}
          style={{ width: 420 }}

        />
        <Popover
          sx={{
            pointerEvents: "none",
          }}
          open={otworzpodpowiedzimie}
          anchorEl={podpowiedzimie}
          anchorOrigin={{
            vertical: "bottom",
            horizontal: "left",
          }}
          transformOrigin={{
            vertical: "top",
            horizontal: "left",
          }}
          onClose={UkryjhPodpowiedzImie}
          disableRestoreFocus
        >
          <Typography sx={{ p: 1 }}>
            Przykład prawidłowej formy imienia: Jan .
          </Typography>
        </Popover>
        <HelpIcon
          color="primary"
          sx={{ fontSize: 30 }}
          style={{ marginLeft: "10px" }}
          onMouseEnter={PokazPodpowiedzImie}
          onMouseLeave={UkryjhPodpowiedzImie}
        />
      </span>

Końcowy efekt działania jest poprawny, czyli po najechaniu na znak zapytania wyświetla się podpowiedź.
screenshot-20221206135035.png

1

Może przez to, że podajesz null do anchorEl?

 const [podpowiedzimie, setpodpowiedzimie] = React.useState(null);
 // ...
 anchorEl={podpowiedzimie}
0
LukeJL napisał(a):

Może przez to, że podajesz null do anchorEl?

 const [podpowiedzimie, setpodpowiedzimie] = React.useState(null);
 // ...
 anchorEl={podpowiedzimie}

Pozmieniałem to teraz na taką formę:

const [podpowiedzimie, setpodpowiedzimie] = React.useState();
const [podpowiedznaziwsko, setpodpowiedznaziwsko] = React.useState();
const [podpowiedznumertelefonu, setpodpowiedznumertelefonu] =  React.useState();

i błąd nadal jest:

  react_devtools_backend.js:4026 MUI: The `anchorEl` prop provided to the component is invalid.
The anchor element should be part of the document layout.
Make sure the element is present in the document or that it's not display none. 
    at PopperTooltip (http://localhost:3000/static/js/bundle.js:31371:5)
    at Portal (http://localhost:3000/static/js/bundle.js:31778:5)
    at PopperUnstyled (http://localhost:3000/static/js/bundle.js:31504:5)
    at http://localhost:3000/static/js/bundle.js:7759:66
    at Popper (http://localhost:3000/static/js/bundle.js:48395:72)
    at http://localhost:3000/static/js/bundle.js:7759:66
    at Tooltip (http://localhost:3000/static/js/bundle.js:55355:83)
    at span
    at div
    at div
    at SnackbarProvider (http://localhost:3000/static/js/bundle.js:126942:24)
    at MenuPiktogramowe (http://localhost:3000/static/js/bundle.js:5635:132)
    at PanelGlowny (http://localhost:3000/static/js/bundle.js:6148:5)
    at Routes (http://localhost:3000/static/js/bundle.js:163942:5)
    at App
    at Router (http://localhost:3000/static/js/bundle.js:163875:15)
    at BrowserRouter (http://localhost:3000/static/js/bundle.js:162684:5)
1
virusek391 napisał(a):

Pozmieniałem to teraz na taką formę:

const [podpowiedzimie, setpodpowiedzimie] = React.useState();

no to teraz podajesz undefined.

Nie znam biblioteki MUI, tym niemniej komunikat wyraźnie ci pisze, co jest nie tak: The anchorEl prop provided to the component is invalid.

może przy renderingu sprawdzać czy podpowiedzimie jest prawdziwe(truthy) i tylko jak jest prawdziwe (a powinno stać się prawdziwe po tym, jak odpalisz setpodpowiedzimie(event.target);), to wyświetlać?

<div>
{
  podpowiedzimie && <Popover anchorEl={podpowiedzimie} ......
}
</div>

jak tam będzie null czy undefined, to będzie to potraktowane jako wartość fałszywa i się nie wyświetli.

0
LukeJL napisał(a):

może przy renderingu sprawdzać czy podpowiedzimie jest prawdziwe(truthy) i tylko jak jest prawdziwe (a powinno stać się prawdziwe po tym, jak odpalisz
setpodpowiedzimie(event.target);), to wyświetlać?

[...]
jak tam będzie null czy undefined, to będzie to potraktowane jako wartość fałszywa i się nie wyświetli.
zmodyfikowałem jeszcze kod w taki sposób i niestety ten sam efekt:

{podpowiedzimie &&  <Popover
  sx={{
    pointerEvents: "none",
  }}
  open={otworzpodpowiedzimie}
  anchorEl={podpowiedzimie}
  anchorOrigin={{
    vertical: "bottom",
    horizontal: "left",
  }}
  transformOrigin={{
    vertical: "top",
    horizontal: "left",
  }}
  onClose={UkryjhPodpowiedzImie}
  disableRestoreFocus
>
  <Typography sx={{ p: 1 }}>
    Przykład prawidłowej formy imienia: Jan .
  </Typography>
</Popover>}

Zmieniłem jeszcze według przykładu z https://codesandbox.io/s/e30c7v?file=/demo.tsx

to:

const [podpowiedzimie, setpodpowiedzimie] = React.useState(null);

na:

const [podpowiedzimie, setpodpowiedzimie] = React.useState<HTMLElement | null>(null);

ale teraz wywala mi taki błąd:

komponent_dodaj_kontrahenta.js:41 Uncaught TypeError: number 0 is not iterable (cannot read property Symbol(Symbol.iterator))
    at KomponentDodajKontrahenta (komponent_dodaj_kontrahenta.js:41:1)
    at renderWithHooks (react-dom.development.js:16305:1)
    at mountIndeterminateComponent (react-dom.development.js:20074:1)
    at beginWork (react-dom.development.js:21587:1)
    at HTMLUnknownElement.callCallback (react-dom.development.js:4164:1)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:4213:1)
    at invokeGuardedCallback (react-dom.development.js:4277:1)
    at beginWork$1 (react-dom.development.js:27451:1)
    at performUnitOfWork (react-dom.development.js:26557:1)
    at workLoopSync (react-dom.development.js:26466:1)
1

@virusek391: To się wszystko bierze z tego, że próbujesz przypisać podpowiedź, wtedy kiedy jej jeszcze nie ma - i biblioteka Cię przed tym ostrzega.

To co przekazujesz do anchorEl w ogóle nie powinno być stanowe, tylko powinno być zrobione jakoś tak:

import Popover from "@mui/material/Popover";

const podpowiedzimie = <HelpIcon
  color="primary"
  sx={{ fontSize: 30 }}
  style={{ marginLeft: "10px" }}
/>;

return <span style={{ display: "flex", alignItems: "center" }}>
  <TextField
    requireds="true"
    id="outlined-required"
    label="Imię"
    value={imie}
    onChange={Przypisz_Imie}
    error={!!tekst_bledu_imie}
    helperText={tekst_bledu_imie}
    style={{ width: 420 }}
  />
  {podpowiedzimie}
  <Popover
    sx={{pointerEvents: "none"}}
    open={otworzpodpowiedzimie}
    onClose={UkryjhPodpowiedzImie}
    anchorEl={podpowiedzimie}
    anchorOrigin={{
      vertical: "bottom",
      horizontal: "left",
    }}
    transformOrigin={{
      vertical: "top",
      horizontal: "left",
    }}
    disableRestoreFocus
  >
    <Typography sx={{ p: 1 }}>
      Przykład prawidłowej formy imienia: Jan .
    </Typography>
  </Popover>
</span>;

Kod poglądowy!! Nie kopiuj go, on jest tylko żeby pokazać zamysł przekazywania anchorEl nie poprzez stan!

Jakieś czary w stanowe property w bibliotece to zawsze jest zły pomysł.

@virusek391: Może po prostu wpisz w google "MUI popover on icon" albo "MUI popover on help icon" i zobacz co znajdziesz?

0
Riddle napisał(a):

@virusek391: To się wszystko bierze z tego, że próbujesz przypisać podpowiedź, wtedy kiedy jej jeszcze nie ma - i biblioteka Cię przed tym ostrzega.

To co przekazujesz do anchorEl w ogóle nie powinno być stanowe, tylko powinno być zrobione jakoś tak:

[...]

Jakieś czary w stanowe property w bibliotece to zawsze jest zły pomysł.

@virusek391: Może po prostu wpisz w google "MUI popover on icon" albo "MUI popover on help icon" i zobacz co znajdziesz?

Zrobiłem tak:

{podpowiedzimie !==null &&  <Popover
    sx={{
      pointerEvents: "none",
    }}
    open={otworzpodpowiedzimie}
    anchorEl={podpowiedzimie}
    anchorOrigin={{
      vertical: "bottom",
      horizontal: "left",
    }}
    transformOrigin={{
      vertical: "top",
      horizontal: "left",
    }}
    onClose={UkryjhPodpowiedzImie}
    disableRestoreFocus
  >
    <Typography sx={{ p: 1 }}>
      Przykład prawidłowej formy imienia: Jan .
    </Typography>
  </Popover> }

i niestety nadal występuje problem. Wcześniejszy kod pisałem sugerując się przykładem podanym ze strony MUI

import * as React from 'react';
import Box from '@mui/material/Box';
import Popper, { PopperPlacementType } from '@mui/material/Popper';
import Typography from '@mui/material/Typography';
import Grid from '@mui/material/Grid';
import Button from '@mui/material/Button';
import Fade from '@mui/material/Fade';
import Paper from '@mui/material/Paper';

export default function PositionedPopper() {
  const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>(null);
  const [open, setOpen] = React.useState(false);
  const [placement, setPlacement] = React.useState<PopperPlacementType>();

  const handleClick =
    (newPlacement: PopperPlacementType) =>
    (event: React.MouseEvent<HTMLButtonElement>) => {
      setAnchorEl(event.currentTarget);
      setOpen((prev) => placement !== newPlacement || !prev);
      setPlacement(newPlacement);
    };

  return (
    <Box sx={{ width: 500 }}>
      <Popper open={open} anchorEl={anchorEl} placement={placement} transition>
        {({ TransitionProps }) => (
          <Fade {...TransitionProps} timeout={350}>
            <Paper>
              <Typography sx={{ p: 2 }}>The content of the Popper.</Typography>
            </Paper>
          </Fade>
        )}
      </Popper>
      <Grid container justifyContent="center">
        <Grid item>
          <Button onClick={handleClick('top-start')}>top-start</Button>
          <Button onClick={handleClick('top')}>top</Button>
          <Button onClick={handleClick('top-end')}>top-end</Button>
        </Grid>
      </Grid>
      <Grid container justifyContent="center">
        <Grid item xs={6}>
          <Button onClick={handleClick('left-start')}>left-start</Button>
          <br />
          <Button onClick={handleClick('left')}>left</Button>
          <br />
          <Button onClick={handleClick('left-end')}>left-end</Button>
        </Grid>
        <Grid item container xs={6} alignItems="flex-end" direction="column">
          <Grid item>
            <Button onClick={handleClick('right-start')}>right-start</Button>
          </Grid>
          <Grid item>
            <Button onClick={handleClick('right')}>right</Button>
          </Grid>
          <Grid item>
            <Button onClick={handleClick('right-end')}>right-end</Button>
          </Grid>
        </Grid>
      </Grid>
      <Grid container justifyContent="center">
        <Grid item>
          <Button onClick={handleClick('bottom-start')}>bottom-start</Button>
          <Button onClick={handleClick('bottom')}>bottom</Button>
          <Button onClick={handleClick('bottom-end')}>bottom-end</Button>
        </Grid>
      </Grid>
    </Box>
  );
}
0
Riddle napisał(a):

@virusek391: To się wszystko bierze z tego, że próbujesz przypisać podpowiedź, wtedy kiedy jej jeszcze nie ma - i biblioteka Cię przed tym ostrzega.

To co przekazujesz do anchorEl w ogóle nie powinno być stanowe, tylko powinno być zrobione jakoś tak:

import Popover from "@mui/material/Popover";

const podpowiedzimie = <HelpIcon
  color="primary"
  sx={{ fontSize: 30 }}
  style={{ marginLeft: "10px" }}
/>;

return <span style={{ display: "flex", alignItems: "center" }}>
  <TextField
    requireds="true"
    id="outlined-required"
    label="Imię"
    value={imie}
    onChange={Przypisz_Imie}
    error={!!tekst_bledu_imie}
    helperText={tekst_bledu_imie}
    style={{ width: 420 }}
  />
  {podpowiedzimie}
  <Popover
    sx={{pointerEvents: "none"}}
    open={otworzpodpowiedzimie}
    onClose={UkryjhPodpowiedzImie}
    anchorEl={podpowiedzimie}
    anchorOrigin={{
      vertical: "bottom",
      horizontal: "left",
    }}
    transformOrigin={{
      vertical: "top",
      horizontal: "left",
    }}
    disableRestoreFocus
  >
    <Typography sx={{ p: 1 }}>
      Przykład prawidłowej formy imienia: Jan .
    </Typography>
  </Popover>
</span>;

Kod poglądowy!! Nie kopiuj go, on jest tylko żeby pokazać zamysł przekazywania anchorEl nie poprzez stan!

Jakieś czary w stanowe property w bibliotece to zawsze jest zły pomysł.

@virusek391: Może po prostu wpisz w google "MUI popover on icon" albo "MUI popover on help icon" i zobacz co znajdziesz?

Zrobiłem jeszcze pewien eksperyment który polegał na tym że dałem komentarz wszędzie tam gdzie występowała linijka z anchorEl={....} i ku mojemu zdziwieniu program nadal wywalał błąd związany z anchorEI. Więc szukałem dalej i okazało się że błąd wyświetla się tylko gdy komponent Dialog z paramentem open ma wartość props, natomiast gdy wstawię tam ręcznie wartość true to nie ma błędu. Oczywiście problemem teraz jest to że komponent nie ukrywa się.

 <Dialog
        open={props.wyswietl}
    
        sx={{
          "& .MuiDialog-container": {
            "& .MuiPaper-root": {
              width: "100%",
              maxWidth: "500px", // Set your width here
            },
          },
        }}
       style={{zIndex:1}}
        PaperProps={{
          style: {
            backgroundColor: "white",
            boxShadow: "none",
          },
        }}
      >
        {(() => {
          switch (props.tryb_pracy) {
            case 1:
              return <DialogTitle>DODAWANIE KONTRAHENTA:</DialogTitle>;
            case 2:
              return <DialogTitle>MODYFIKOWANIE KONTRAHENTA:</DialogTitle>;
            default:
              return <DialogTitle>DODAWANIE KONTRAHENTA:</DialogTitle>;
          }
        })()}

        <DialogContent>
          <Stack spacing={2}>
            <span className="odstep_od_gory"> </span>
            <span style={{ display: "flex", alignItems: "center" }}>
              <TextField
                requireds="true"
                id="outlined-required"
                label="Imię"
                // maxWidth="500"
                // minWidth="500"
                value={imie}
                onChange={Przypisz_Imie}
                error={!!tekst_bledu_imie}
                helperText={tekst_bledu_imie}
                style={{ width: 420 }}
                // onMouseEnter={handlePopoverOpen}
                //onMouseLeave={handlePopoverClose}
              />

       
            </span>

            <span style={{ display: "flex", alignItems: "center" }}>
              <TextField
                requireds="true"
                id="outlined-required"
                label="Nazwisko"
                onChange={Przypisz_Nazwisko}
                value={nazwisko}
                error={!!tekst_bledu_nazwisko}
                helperText={tekst_bledu_nazwisko}
                style={{ width: 420 }}
              />
            
            </span>
            <span style={{ display: "flex", alignItems: "center" }}>
              <TextField
                requireds="true"
                id="outlined-required"
                label="Numer telefonu"
                onChange={Przypisz_Numer_Telefonu}
                value={numertelefonu}
                error={!!tekst_bledu_numer_telefonu}
                helperText={tekst_bledu_numer_telefonu}
                InputProps={{
                  startAdornment: (
                    <InputAdornment position="start">+48</InputAdornment>
                  ),
                }}
                style={{ width: 420 }}
              ></TextField>
             </span>

            <span className="odstep_od_gory"> </span>
          </Stack>

          <span style={{ paddingRight: 10 }}>
            {(() => {
              switch (props.tryb_pracy) {
                case 1:
                  return (
                    <Button
                      variant="contained"
                      onClick={przycisk_dodaj_kontrahenta}
                    >
                      ZAPISZ
                    </Button>
                  );

                default:
                  return (
                    <Button
                      variant="contained"
                      onClick={przycisk_dodaj_kontrahenta}
                    >
                      ZAPISZ
                    </Button>
                  );
              }
            })()}
          </span>
          <Button variant="contained" onClick={(e) => PrzyciskAnuluj()}>
            ANULUJ
          </Button>
        </DialogContent>
      </Dialog>

1 użytkowników online, w tym zalogowanych: 0, gości: 1