Using SSR in my React/Next app.
Trying to find an element with the id but is returning null
even when document is present (and I can see the div with the id plTable),
and even when getElementById is called after 6 seconds to ensure the element has been loaded on screen.
What is the issue and how can I fix this?
Here is the component:
const LineItemTable: React.FC<LineItemTableProps> = ({ reportName }) => {
const classes = useStyles({});
const dispatch = useDispatch();
const [page, setPage] = useState<number>(0);
const selectedCompanyId = useSelector((state) => state.company.selectedId);
const company = useSelector((state) => state.company.current);
useEffect(() => {
if (reportName && selectedCompanyId) {
dispatch(
getReportByName({
name: reportName, // 'profit and loss' or 'balance sheet'
includeLineItems: true,
page: page,
}),
);
}
}, [reportName, selectedCompanyId]);
let plTable: any = 'kk';
useEffect(() => {
console.log('uef');
if (typeof document !== 'undefined') {
setTimeout(() => {
plTable = document.querySelector('plTable');// ***** NEVER FOUND ******
console.log('doc', document); // ***** is found and defined correctly *****
console.log('plTable', plTable); // ***** null *****
}, 6000);
}
});
const endObserver = new IntersectionObserver(
(entries) => {
const [entry] = entries;
if (!entry.isIntersecting) {
//Put what you want to happen if the end is NOT visible
console.log('not visible');
} else {
//Put what you want to happen if the end is visible
//For instance firing your function
// setPage(page 1);
console.log('visible');
}
},
{ root: null, threshold: 1 },
);
// endObserver.observe(plTable);
const getLineItems = useMemo(() => makeGetAllLineItemsByReport(reportName), [
reportName,
]);
const lineItems = useSelector((state) => getLineItems(state));
if (!lineItems) return null;
// ADDED
// Add an elemnt in your html with the class of "end" at the end of the chart
// I recommend adding an empty div with the class of "end" and setting it's opacity to 0
return (
<div
id="plTable" // ****** Defined here *******
style={{
display: 'flex',
alignItems: 'flex-end',
margin: 'auto 0px',
}}
>
<Grid container spacing={3}>
<Grid item xs={12}>
<Card
sx={{
padding: '20px',
}}
>
<CardContent
sx={{
alignItems: 'center',
display: 'flex',
height: '1000px',
}}
>
<Scrollbar className={classes.scrollBar}>
<Table className={classes.root}>
<TableHead>
<TableRow>
<th>
<TableCell className={classes.headerStyle}>
ANALYSIS CATEGORY
</TableCell>
<TableCell
className={classes.headerStyle}
sx={{ marginRight: '10px' }}
>
NAME
</TableCell>
{company &&
company.dates.map((header) => (
<TableCell
className={classes.headerStyle}
sx={{
width: '200px !important',
marginLeft: '10px',
}}
key={header}
>
{header}
</TableCell>
))}
</th>
</TableRow>
</TableHead>
<TableBody>
{lineItems.map((lineItem, i) => (
<TableRow key={lineItem.id}>
<LineItemRow
i={i}
id={lineItem.id}
reportName={reportName}
level={lineItem.level}
/>
</TableRow>
))}
</TableBody>
</Table>
</Scrollbar>
</CardContent>
</Card>
</Grid>
</Grid>
</div>
);
};
CodePudding user response:
According to MDN docs, querySelector
either takes an element to look for:
querySelector('plTable')
/* Looking for html tag plTable */
or an identifier:
querySelector('#plTable')
/* Looking for an element with id of plTable */
CodePudding user response:
Don't use DOM selectors in React, use refs
to access DOM nodes.
You can create a ref with useRef
or React.createRef
or you can pass a callback to the ref
attribute of an element, that will receive the DOM node reference when the virtual DOM has done with the reconciliation.
To check if the node is mounted and do something with it being sure it is mounted, try this:
<div
id="plTable" // ****** Defined here *******
style={{
display: 'flex',
alignItems: 'flex-end',
margin: 'auto 0px',
}}
ref={node => {
if (node) console.log("p1Table", node)
//Do something with node
}}
>