KevinVandy/material-react-table

When using `localStorage` or `sessionStorage` to store filter values, I'm encountering an error specifically with the `filterVariant` set to "date" or "date-range":

Closed this issue · 5 comments

material-react-table version

v2

react & react-dom versions

18

Describe the bug and the steps to reproduce it

When using localStorage or sessionStorage to store filter values, I'm encountering an error specifically with the filterVariant set to "date" or "date-range":

{
  accessorKey: "date_of_birth",
  header: "DOB",
  filterVariant: "date",
},
{
  accessorKey: "employment_period",
  header: "Employment Period",
  filterVariant: "date-range",
}

The error message is:

Uncaught TypeError: value.isValid is not a function
    at AdapterDayjs.isValid (@mui_x-date-pickers_AdapterDayjs.js?v=80b53281:550:20)
    at Object.getTimezone (chunk-M5HLDI5W.js?v=80b53281:957:58)
    at chunk-M5HLDI5W.js?v=80b53281:1839:59
    at updateMemo (chunk-ZW7WJ6XU.js?v=80b53281:12833:27)
    at Object.useMemo (chunk-ZW7WJ6XU.js?v=80b53281:13349:24)
    at Object.useMemo (chunk-4D5CYJYK.js?v=80b53281:1094:29)
    at useValueWithTimezone (chunk-M5HLDI5W.js?v=80b53281:1839:32)
    at usePickerValue (chunk-M5HLDI5W.js?v=80b53281:2018:7)
    at usePicker (chunk-M5HLDI5W.js?v=80b53281:2513:31)
    at useDesktopPicker (chunk-M5HLDI5W.js?v=80b53281:3079:7)

Additionally, the error occurs in the <ForwardRef(DesktopDatePicker2)> component:

console.js:273 The above error occurred in the <ForwardRef(DesktopDatePicker2)> component:
 
    at DesktopDatePicker2 (http://localhost:5173/node_modules/.vite/deps/chunk-M5HLDI5W.js?v=80b53281:10204:22)
    at DatePicker2 (http://localhost:5173/node_modules/.vite/deps/chunk-VIR5TUWY.js?v=80b53281:649:17)
    at MRT_FilterTextField (http://localhost:5173/node_modules/.vite/deps/material-react-table.js?v=80b53281:7453:9)
    at div
    at http://localhost:5173/node_modules/.vite/deps/chunk-SGSCRMHX.js?v=80b53281:1670:50
    at div
    at http://localhost:5173/node_modules/.vite/deps/chunk-SGSCRMHX.js?v=80b53281:1670:50
    at div
    at http://localhost:5173/node_modules/.vite/deps/chunk-SGSCRMHX.js?v=80b53281:1670:50
    at Transition2 (http://localhost:5173/node_modules/.vite/deps/chunk-7VJMO7CQ.js?v=80b53281:915:30)
    at Collapse2 (http://localhost:5173/node_modules/.vite/deps/chunk-YM4NOO7R.js?v=80b53281:209:17)
    at MRT_TableHeadCellFilterContainer (http://localhost:5173/node_modules/.vite/deps/material-react-table.js?v=80b53281:7685:9)
    at th
    at http://localhost:5173/node_modules/.vite/deps/chunk-SGSCRMHX.js?v=80b53281:1670:50
    at TableCell2 (http://localhost:5173/node_modules/.vite/deps/chunk-YM4NOO7R.js?v=80b53281:7884:17)
    at MRT_TableHeadCell (http://localhost:5173/node_modules/.vite/deps/material-react-table.js?v=80b53281:7814:9)
    at tr
    at http://localhost:5173/node_modules/.vite/deps/chunk-SGSCRMHX.js?v=80b53281:1670:50
    at TableRow2 (http://localhost:5173/node_modules/.vite/deps/chunk-YM4NOO7R.js?v=80b53281:8332:17)
    at MRT_TableHeadRow (http://localhost:5173/node_modules/.vite/deps/material-react-table.js?v=80b53281:7916:9)
    at thead
    at http://localhost:5173/node_modules/.vite/deps/chunk-SGSCRMHX.js?v=80b53281:1670:50
    at TableHead2 (http://localhost:5173/node_modules/.vite/deps/chunk-YM4NOO7R.js?v=80b53281:8217:17)
    at MRT_TableHead (http://localhost:5173/node_modules/.vite/deps/material-react-table.js?v=80b53281:7962:9)
    at table
    at http://localhost:5173/node_modules/.vite/deps/chunk-SGSCRMHX.js?v=80b53281:1670:50
    at Table2 (http://localhost:5173/node_modules/.vite/deps/chunk-YM4NOO7R.js?v=80b53281:7602:17)
    at MRT_Table (http://localhost:5173/node_modules/.vite/deps/material-react-table.js?v=80b53281:7980:9)
    at div
    at http://localhost:5173/node_modules/.vite/deps/chunk-SGSCRMHX.js?v=80b53281:1670:50
    at TableContainer2 (http://localhost:5173/node_modules/.vite/deps/chunk-YM4NOO7R.js?v=80b53281:8035:17)
    at MRT_TableContainer (http://localhost:5173/node_modules/.vite/deps/material-react-table.js?v=80b53281:8099:9)
    at div
    at http://localhost:5173/node_modules/.vite/deps/chunk-SGSCRMHX.js?v=80b53281:1670:50
    at Paper2 (http://localhost:5173/node_modules/.vite/deps/chunk-7VJMO7CQ.js?v=80b53281:683:17)
    at MRT_TablePaper (http://localhost:5173/node_modules/.vite/deps/material-react-table.js?v=80b53281:8494:9)
    at MaterialReactTable (http://localhost:5173/node_modules/.vite/deps/material-react-table.js?v=80b53281:8521:7)
    at div
    at http://localhost:5173/node_modules/.vite/deps/chunk-SGSCRMHX.js?v=80b53281:1670:50
    at Container3 (http://localhost:5173/node_modules/.vite/deps/chunk-SGSCRMHX.js?v=80b53281:11302:19)
    at App (http://localhost:5173/src/App.jsx?t=1715976427848:27:33)
    at LocalizationProvider2 (http://localhost:5173/node_modules/.vite/deps/chunk-FLERQT5G.js?v=80b53281:34:17)

Consider adding an error boundary to your component tree to customize error handling behavior. Visit React Error Boundaries to learn more about error boundaries.

Any insights or solutions to this issue would be greatly appreciated.

Minimal, Reproducible Example - (Optional, but Recommended)

localstorage-table.zip

Screenshots or Videos (Optional)

No response

Do you intend to try to help solve this bug with your own PR?

None

Terms

  • I understand that if my bug cannot be reliably reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.
Vite-React.1.mp4

I'm also facing the same issue the same npm package .i.e. datepicker
in with the filterVariant set to "date" or "date-range"

https://www.material-react-table.com/docs/guides/state-management

import React from "react";
import ReactDOM from "react-dom/client";
import dayjs from "dayjs";
import "dayjs/locale/en-gb";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
import { CssBaseline, GlobalStyles } from "@mui/material";

import "@fontsource/roboto/300.css";
import "@fontsource/roboto/400.css";
import "@fontsource/roboto/500.css";
import "@fontsource/roboto/700.css";
import App from "./App.jsx";
import "./index.css";
import isSameOrBefore from "dayjs/plugin/isSameOrBefore";
import * as localizedFormat from "dayjs/plugin/localizedFormat";

dayjs.extend(localizedFormat);
dayjs.locale("en-gb");
dayjs.extend(isSameOrBefore);

ReactDOM.createRoot(document.getElementById("root")).render(
  <>
    <LocalizationProvider dateAdapter={AdapterDayjs} adapterLocale="en-gb">
      <CssBaseline />
      <GlobalStyles styles={{ body: { backgroundColor: "#f1f1f1" } }} />
      <App />
    </LocalizationProvider>
  </>
);


import { useEffect, useRef, useState } from "react";
import { Button } from "@mui/material";
import { MaterialReactTable } from "material-react-table";
import { data } from "./makeData";

//column definitions...
const columns = [
  {
    accessorKey: "firstName",
    header: "First Name",
  },
  {
    accessorKey: "lastName",
    header: "Last Name",
  },
  {
    accessorKey: "city",
    header: "City",
  },
  {
    accessorKey: "state",
    header: "State",
  },
  {
    accessorKey: "salary",
    header: "Salary",
  },
  {
    accessorKey: "date",
    header: "Date",
    filterVariant: "date",
  },
];
//end

const Example = () => {
  const isFirstRender = useRef(true);

  const [columnFilters, setColumnFilters] = useState([]);
  const [columnVisibility, setColumnVisibility] = useState({});
  const [density, setDensity] = useState("comfortable");
  const [globalFilter, setGlobalFilter] = useState(undefined);
  const [showGlobalFilter, setShowGlobalFilter] = useState(false);
  const [showColumnFilters, setShowColumnFilters] = useState(false);
  const [sorting, setSorting] = useState([]);

  //load state from local storage
  useEffect(() => {
    const columnFilters = sessionStorage.getItem("mrt_columnFilters_table_1");
    const columnVisibility = sessionStorage.getItem(
      "mrt_columnVisibility_table_1"
    );
    const density = sessionStorage.getItem("mrt_density_table_1");
    const globalFilter = sessionStorage.getItem("mrt_globalFilter_table_1");
    const showGlobalFilter = sessionStorage.getItem(
      "mrt_showGlobalFilter_table_1"
    );
    const showColumnFilters = sessionStorage.getItem(
      "mrt_showColumnFilters_table_1"
    );
    const sorting = sessionStorage.getItem("mrt_sorting_table_1");

    if (columnFilters) {
      setColumnFilters(JSON.parse(columnFilters));
    }
    if (columnVisibility) {
      setColumnVisibility(JSON.parse(columnVisibility));
    }
    if (density) {
      setDensity(JSON.parse(density));
    }
    if (globalFilter) {
      setGlobalFilter(JSON.parse(globalFilter) || undefined);
    }
    if (showGlobalFilter) {
      setShowGlobalFilter(JSON.parse(showGlobalFilter));
    }
    if (showColumnFilters) {
      setShowColumnFilters(JSON.parse(showColumnFilters));
    }
    if (sorting) {
      setSorting(JSON.parse(sorting));
    }
    isFirstRender.current = false;
  }, []);

  //save states to local storage
  useEffect(() => {
    if (isFirstRender.current) return;
    sessionStorage.setItem(
      "mrt_columnFilters_table_1",
      JSON.stringify(columnFilters)
    );
  }, [columnFilters]);

  useEffect(() => {
    if (isFirstRender.current) return;
    sessionStorage.setItem(
      "mrt_columnVisibility_table_1",
      JSON.stringify(columnVisibility)
    );
  }, [columnVisibility]);

  useEffect(() => {
    if (isFirstRender.current) return;
    sessionStorage.setItem("mrt_density_table_1", JSON.stringify(density));
  }, [density]);

  useEffect(() => {
    if (isFirstRender.current) return;
    sessionStorage.setItem(
      "mrt_globalFilter_table_1",
      JSON.stringify(globalFilter ?? "")
    );
  }, [globalFilter]);

  useEffect(() => {
    if (isFirstRender.current) return;
    sessionStorage.setItem(
      "mrt_showGlobalFilter_table_1",
      JSON.stringify(showGlobalFilter)
    );
  }, [showGlobalFilter]);

  useEffect(() => {
    if (isFirstRender.current) return;
    sessionStorage.setItem(
      "mrt_showColumnFilters_table_1",
      JSON.stringify(showColumnFilters)
    );
  }, [showColumnFilters]);

  useEffect(() => {
    if (isFirstRender.current) return;
    sessionStorage.setItem("mrt_sorting_table_1", JSON.stringify(sorting));
  }, [sorting]);

  const resetState = () => {
    sessionStorage.removeItem("mrt_columnFilters_table_1");
    sessionStorage.removeItem("mrt_columnVisibility_table_1");
    sessionStorage.removeItem("mrt_density_table_1");
    sessionStorage.removeItem("mrt_globalFilter_table_1");
    sessionStorage.removeItem("mrt_showGlobalFilter_table_1");
    sessionStorage.removeItem("mrt_showColumnFilters_table_1");
    sessionStorage.removeItem("mrt_sorting_table_1");
    window.location.reload();
  };

  return (
    <MaterialReactTable
      columns={columns}
      data={data}
      onColumnFiltersChange={setColumnFilters}
      onColumnVisibilityChange={setColumnVisibility}
      onDensityChange={setDensity}
      onGlobalFilterChange={setGlobalFilter}
      onShowColumnFiltersChange={setShowColumnFilters}
      onShowGlobalFilterChange={setShowGlobalFilter}
      onSortingChange={setSorting}
      state={{
        columnFilters,
        columnVisibility,
        density,
        globalFilter,
        showColumnFilters,
        showGlobalFilter,
        sorting,
      }}
      renderTopToolbarCustomActions={() => (
        <Button onClick={resetState}>Reset State</Button>
      )}
    />
  );
};

export default Example;


// Type definition for a Person
// In JavaScript, we typically use JSDoc comments to describe types

/**
 * @typedef {Object} Person
 * @property {string} firstName
 * @property {string} lastName
 * @property {string} city
 * @property {string} state
 * @property {number} salary
 * @property {string} date - The date field in ISO 8601 format
 */

// Mock data
export const data = [
  {
    firstName: "Allison",
    lastName: "Brown",
    city: "Omaha",
    state: "Nebraska",
    salary: 10000,
    date: "2024-01-01T18:30:00.000Z",
  },
  {
    firstName: "Harry",
    lastName: "Smith",
    city: "Hickman",
    state: "Nebraska",
    salary: 20000,
    date: "2024-02-01T18:30:00.000Z",
  },
  {
    firstName: "Sally",
    lastName: "Williamson",
    city: "Alliance",
    state: "Nebraska",
    salary: 30000,
    date: "2024-03-01T18:30:00.000Z",
  },
  {
    firstName: "Lebron",
    lastName: "James",
    city: "Indianapolis",
    state: "Indiana",
    salary: 40000,
    date: "2024-04-01T18:30:00.000Z",
  },
  {
    firstName: "Michael",
    lastName: "McGinnis",
    city: "Harrisonburg",
    state: "Virginia",
    salary: 150000,
    date: "2024-05-01T18:30:00.000Z",
  },
  {
    firstName: "Joseph",
    lastName: "Williams",
    city: "Valentine",
    state: "Nebraska",
    salary: 100000,
    date: "2024-06-01T18:30:00.000Z",
  },
  {
    firstName: "Noah",
    lastName: "Brown",
    city: "Toledo",
    state: "Ohio",
    salary: 50000,
    date: "2024-07-01T18:30:00.000Z",
  },
  {
    firstName: "Mason",
    lastName: "Zhang",
    city: "Sacramento",
    state: "California",
    salary: 100000,
    date: "2024-08-01T18:30:00.000Z",
  },
  {
    firstName: "Violet",
    lastName: "Doe",
    city: "San Francisco",
    state: "California",
    salary: 100000,
    date: "2024-09-01T18:30:00.000Z",
  },
];

chunk-ZW7WJ6XU.js?v=80b53281:14036 The above error occurred in the <ForwardRef(DesktopDatePicker2)> component:

    at DesktopDatePicker2 (http://localhost:5173/node_modules/.vite/deps/chunk-M5HLDI5W.js?v=80b53281:10204:22)
    at DatePicker2 (http://localhost:5173/node_modules/.vite/deps/chunk-VIR5TUWY.js?v=80b53281:649:17)
    at MRT_FilterTextField (http://localhost:5173/node_modules/.vite/deps/material-react-table.js?v=80b53281:7453:9)
    at div
    at http://localhost:5173/node_modules/.vite/deps/chunk-SGSCRMHX.js?v=80b53281:1670:50
    at div
    at http://localhost:5173/node_modules/.vite/deps/chunk-SGSCRMHX.js?v=80b53281:1670:50
    at div
    at http://localhost:5173/node_modules/.vite/deps/chunk-SGSCRMHX.js?v=80b53281:1670:50
    at Transition2 (http://localhost:5173/node_modules/.vite/deps/chunk-7VJMO7CQ.js?v=80b53281:915:30)
    at Collapse2 (http://localhost:5173/node_modules/.vite/deps/chunk-YM4NOO7R.js?v=80b53281:209:17)
    at MRT_TableHeadCellFilterContainer (http://localhost:5173/node_modules/.vite/deps/material-react-table.js?v=80b53281:7685:9)
    at th
    at http://localhost:5173/node_modules/.vite/deps/chunk-SGSCRMHX.js?v=80b53281:1670:50
    at TableCell2 (http://localhost:5173/node_modules/.vite/deps/chunk-YM4NOO7R.js?v=80b53281:7884:17)
    at MRT_TableHeadCell (http://localhost:5173/node_modules/.vite/deps/material-react-table.js?v=80b53281:7814:9)
    at tr
    at http://localhost:5173/node_modules/.vite/deps/chunk-SGSCRMHX.js?v=80b53281:1670:50
    at TableRow2 (http://localhost:5173/node_modules/.vite/deps/chunk-YM4NOO7R.js?v=80b53281:8332:17)
    at MRT_TableHeadRow (http://localhost:5173/node_modules/.vite/deps/material-react-table.js?v=80b53281:7916:9)
    at thead
    at http://localhost:5173/node_modules/.vite/deps/chunk-SGSCRMHX.js?v=80b53281:1670:50
    at TableHead2 (http://localhost:5173/node_modules/.vite/deps/chunk-YM4NOO7R.js?v=80b53281:8217:17)
    at MRT_TableHead (http://localhost:5173/node_modules/.vite/deps/material-react-table.js?v=80b53281:7962:9)
    at table
    at http://localhost:5173/node_modules/.vite/deps/chunk-SGSCRMHX.js?v=80b53281:1670:50
    at Table2 (http://localhost:5173/node_modules/.vite/deps/chunk-YM4NOO7R.js?v=80b53281:7602:17)
    at MRT_Table (http://localhost:5173/node_modules/.vite/deps/material-react-table.js?v=80b53281:7980:9)
    at div
    at http://localhost:5173/node_modules/.vite/deps/chunk-SGSCRMHX.js?v=80b53281:1670:50
    at TableContainer2 (http://localhost:5173/node_modules/.vite/deps/chunk-YM4NOO7R.js?v=80b53281:8035:17)
    at MRT_TableContainer (http://localhost:5173/node_modules/.vite/deps/material-react-table.js?v=80b53281:8099:9)
    at div
    at http://localhost:5173/node_modules/.vite/deps/chunk-SGSCRMHX.js?v=80b53281:1670:50
    at Paper2 (http://localhost:5173/node_modules/.vite/deps/chunk-7VJMO7CQ.js?v=80b53281:683:17)
    at MRT_TablePaper (http://localhost:5173/node_modules/.vite/deps/material-react-table.js?v=80b53281:8494:9)
    at MaterialReactTable (http://localhost:5173/node_modules/.vite/deps/material-react-table.js?v=80b53281:8521:7)
    at Example (http://localhost:5173/src/App.jsx?t=1716067355910:51:25)
    at LocalizationProvider2 (http://localhost:5173/node_modules/.vite/deps/chunk-FLERQT5G.js?v=80b53281:34:17)

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
chunk-ZW7WJ6XU.js?v=80b53281:19409 Uncaught TypeError: value.isValid is not a function
    at AdapterDayjs.isValid (@mui_x-date-pickers_…s?v=80b53281:550:20)
    at Object.getTimezone (chunk-M5HLDI5W.js?v=80b53281:957:58)
    at chunk-M5HLDI5W.js?v=80b53281:1839:59
    at mountMemo (chunk-ZW7WJ6XU.js?v=80b53281:12817:27)
    at Object.useMemo (chunk-ZW7WJ6XU.js?v=80b53281:13141:24)
    at Object.useMemo (chunk-4D5CYJYK.js?v=80b53281:1094:29)
    at useValueWithTimezone (chunk-M5HLDI5W.js?v=80b53281:1839:32)
    at usePickerValue (chunk-M5HLDI5W.js?v=80b53281:2018:7)
    at usePicker (chunk-M5HLDI5W.js?v=80b53281:2513:31)
    at useDesktopPicker (chunk-M5HLDI5W.js?v=80b53281:3079:7)



This would not have anything to do with MRT, but instead how you are parsing and storing dates. Dates are objects that cannot be serialized unless to do it properly in a string format yourself.