'Chrome Extension with React + MaterialUI - Table did not get filled with data

I am currently building a browser extension. I am struggling with showing data in a table (which is created with MatarialUI and React). I don't get any errors. Everything else gets rendered perfectly, and the console output displays that the data is present and in the correct format. So, I do not know where my mistake is. Maybe someone sees it and can help me.

options.tsx (produces the option.js and option.html for the browser extension)

import React from 'react';
import ReactDOM from 'react-dom';
import { Box, Card, CardContent, Typography, Grid } from '@material-ui/core';
import 'fontsource-roboto';
import './options.css';
import WhitelistTable from './whitelist';

const Options: React.FC<{}> = () => {
  return (
    <>
      <Box mx={'4px'} my={'16px'}>
        <Card>
          <CardContent>
            <Grid
              container
              direction="column"
              alignItems="center"
              justifyContent="center"
            >
              <Grid item>
                <Typography variant="h3">SOMENAME</Typography>
              </Grid>
              <Grid item>
                <img id="option-logo" src="images/shield_green.png" />
              </Grid>
            </Grid>
          </CardContent>
        </Card>
      </Box>
      <Box mx={'4px'} my={'16px'}>
        <Card>
          <CardContent>
            <WhitelistTable />
          </CardContent>
        </Card>
      </Box>
    </>
  );
};

const root = document.createElement('div');
document.body.appendChild(root);
ReactDOM.render(<Options />, root);

whitelist.tsx (generates the Table)

import * as React from 'react';
import { WLstruc, getStoredID, getStoredWhitelist } from '../utils/storage';
import { alpha, useTheme } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
import TableCell from '@mui/material/TableCell';
import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead';
import TableFooter from '@mui/material/TableFooter';
import TablePagination from '@mui/material/TablePagination';
import TableRow from '@mui/material/TableRow';
import TableSortLabel from '@mui/material/TableSortLabel';
import MaterialTable from 'material-table';
import Toolbar from '@mui/material/Toolbar';
import Typography from '@mui/material/Typography';
import Paper from '@mui/material/Paper';
import Checkbox from '@mui/material/Checkbox';
import IconButton from '@mui/material/IconButton';
import KeyboardArrowLeft from '@mui/icons-material/KeyboardArrowLeft';
import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight';
import FirstPageIcon from '@mui/icons-material/FirstPage';
import LastPageIcon from '@mui/icons-material/LastPage';
import Tooltip from '@mui/material/Tooltip';
import FormControlLabel from '@mui/material/FormControlLabel';
import Switch from '@mui/material/Switch';
import DeleteIcon from '@mui/icons-material/Delete';
import FilterListIcon from '@mui/icons-material/FilterList';
import { visuallyHidden } from '@mui/utils';

export default function Whitelist() {

  const [whitelist, getWhitelist] = React.useState<WLstruc | null>(null);

  React.useEffect(() => {
    getStoredWhitelist().then((whitelist) => getWhitelist(whitelist));
  }, []);

  if (!whitelist) {
    return null;
  }

  console.log(whitelist);

  return (
    <>
      <TableContainer>
        <Table>
          <TableHead>
            <TableRow>
              <TableCell>URL</TableCell>
              <TableCell>Date added</TableCell>
              <TableCell>Expire</TableCell>
              <TableCell>Actions</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            <TableRow key={whitelist.id}>
              <TableCell>{whitelist.url}</TableCell>
              <TableCell>{whitelist.date_added}</TableCell>
              <TableCell>{whitelist.expire}</TableCell>
              <TableCell>
                <IconButton aria-label="delete">
                  <DeleteIcon />
                </IconButton>
              </TableCell>
            </TableRow>
          </TableBody>
          <TableFooter>
            <TableRow>
            </TableRow>
          </TableFooter>
        </Table>
      </TableContainer>
    </>
  );
}

storage.ts (to get the data from the Chrome API)

export interface WLstruc {
  id: number;
  url: string;
  date_added: string;
  expire: boolean;
}

export function getStoredWhitelist(): Promise<WLstruc> {
  return new Promise((resolve) => {
    chrome.storage.local.get({ whitelist: [] }, (res) => {
      resolve(res.whitelist);
    });
  });
}

console output

(4) [{…}, {…}, {…}, {…}]
0: {date_added: '20220313', expire: false, id: 1, url: 'https://google.com/'}
1: {date_added: '20220313', expire: false, id: 2, url: 'https://apple.com/'}
2: {date_added: '20220313', expire: false, id: 3, url: 'https://microsoft.com/'}
3: {date_added: '20220313', expire: false, id: 4, url: 'https://cloudflare.com/'}
length: 4
[[Prototype]]: Array(0)

(Picture) The rendered table



Solution 1:[1]

Thank you @wOxxOm for your help. Now it works. But, the solution is weird and a bit different as you recommended.

I changed

const [whitelist, getWhitelist] = React.useState<WLstruc | null>(null);

to

const [whitelist, getWhitelist] = React.useState<any | null>(null);

and I modified

export function getStoredWhitelist(): Promise<WLstruc> {
  return new Promise((resolve) => {
    chrome.storage.local.get({ whitelist: [] }, (res) => {
      resolve(res.whitelist);
    });
  });
}

to

export function getStoredWhitelist(): Promise<any> {
  return new Promise((resolve) => {
    chrome.storage.local.get({ whitelist: [] }, (res) => {
      resolve(res.whitelist);
    });
  });
}

And finally, I loop with map through the array

{whitelist.map((row, index) => {
              return (
                <TableRow id={row.id}>
                  <TableCell>{row.url}</TableCell>
                  <TableCell>{row.date_added}</TableCell>
                  <TableCell>{row.expire}</TableCell>
                  <TableCell>
                    <IconButton aria-label="delete">
                      <DeleteIcon />
                    </IconButton>
                  </TableCell>
                </TableRow>
              );
            })}

As recommended to remove the line

if (!whitelist) { return null; }

and/or changing the Hook to const [whitelist, getWhitelist] = React.useState<any>(); the program crashes and I get an error ("Uncaught TypeError: Cannot read properties of undefined (reading 'whitelist')"). When I keep it, everything works fine. Now my storage is shown in the table:

Table after the modification

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Shiro