2

I'm getting an error here when I add a moment

import moment from "moment";

const filtersDefaultState = {
 text: "",
 sortBy: "date",
 startDate: moment().startOf("month"),
 endDate: moment().endOf("month"),
};

so I solve this by adding defaultMiddlewareConfig to my configurestore.js file

import { configureStore, createSlice } from "@reduxjs/toolkit";
import expensesReducer from "../reducers/expenses";
import filtersReducer from "../reducers/filters";

const defaultMiddlewareConfig = {
  serializableCheck: {
    ignoredPaths: ["filters.startDate", "filters.endDate"],
  }
};

export default () => {
  const store = configureStore({
    reducer: {
      expenses: expensesReducer,
      filters: filtersReducer,
    },
    middleware: (getDefaultMiddleware) =>
      getDefaultMiddleware(defaultMiddlewareConfig),
  });
  return store;
};

after that, the code works fine until using DateRangePicker returns an error react_devtools_backend.js:2655 A non-serializable value was detected in an action, in the path: startDate. Value and A non-serializable value was detected in an action, in the path: endDate. Value

also if I added toISOString(true) to moment it's retruns an error

import moment from "moment";

const filtersDefaultState = {
  text: "",
  sortBy: "date",
  startDate: moment().startOf("month").toISOString(true),
  endDate: moment().endOf("month").toISOString(true),
};

Uncaught TypeError: startDate.isSameOrBefore is not a function and Uncaught TypeError: endDate.isSameOrAfter is not a function

import moment from "moment";

export default (expenses, { text, sortBy, startDate, endDate }) => {
  return expenses
    .filter((expense) => {
      const creadtedAtMoment = moment(expense.creadtedAt);

      const startDateMatch = startDate
        ? startDate.isSameOrBefore(creadtedAtMoment, "day")
        : true;

      const endDateMatch = endDate
        ? endDate.isSameOrAfter(creadtedAtMoment, "day")
        : true;
      const textMatch = expense.description
        .toLowerCase()
        .includes(text.toLowerCase());

      return startDateMatch && endDateMatch && textMatch;
    })
    .sort((a, b) => {
      if (sortBy === "date") {
        return a.createdAt < b.createdAt ? 1 : -1;
      } else if (sortBy === "amount") {
        return a.amount < b.amount ? 1 : -1;
      }
    });
};

in this file I'm using DateRangePicker

import React from "react";
import { DateRangePicker } from "react-dates";
import { connect } from "react-redux";
import {
  setEndDate,
  setStartDate,
  setTextFilter,
  sortByAmount,
  sortByDate,
} from "../actions/filters";

class ExpenseListfilters extends React.Component {
  state = {
    calenderFocuesd: null,
  };
  onDatesChange = ({ startDate, endDate }) => {
    this.props.dispatch(setStartDate(startDate));
    this.props.dispatch(setEndDate(endDate));
  };
  onFocusChange = (calenderFocuesd) => {
    this.setState(() => ({ calenderFocuesd }));
  };
  render() {
    return (
      <div>
        <input
          text="text"
          value={this.props.filters.text}
          onChange={(e) => {
            this.props.dispatch(setTextFilter(e.target.value));
          }}
        />
        <select
          value={this.props.filters.sortBy}
          onChange={(e) => {
            if (e.target.value === "date") {
              this.props.dispatch(sortByDate());
            } else if (e.target.value) {
              this.props.dispatch(sortByAmount());
            }
          }}
        >
          <option value="date">Date</option>
          <option value="amount">Amount</option>
        </select>
        <DateRangePicker
          startDate={this.props.filters.startDate}
          endDate={this.props.filters.endDate}
          onDatesChange={this.onDatesChange}
          focusedInput={this.state.calenderFocuesd}
          onFocusChange={this.onFocusChange}
          showClearDates={true}
          numberOfMonths={1}
          isOutsideRange={() => false}
          startDateId="MyDatePickerStart"
          endDateId="MyDatePickerEnd"
        />
      </div>
    );
  }
}

const mapStateToProps = (state) => {
  return {
    filters: state.filters,
  };
};

export default connect(mapStateToProps)(ExpenseListfilters);

As I mentioned above I tried these solutions but can't solve other problems

XED
  • 53
  • 5

1 Answers1

0

If you are stringifying the momentjs datetime objects to be stored in the store, then they should be converted back to momentjs datetime objects for the UI if that's what it needs.

Example:

import moment from "moment";

...

const mapStateToProps = (state) => ({
  filters: {
    ...state.filters,
    startDate: moment(state.filters.startDate),
    endDate: moment(state.filters.endDate),
  },
});

The change handler will likely also need to again stringify the datetime objects when dispatched to the store.

onDatesChange = ({ startDate, endDate }) => {
  this.props.dispatch(setStartDate(startDate.toISOString(true)));
  this.props.dispatch(setEndDate(endDate.toISOString(true)));
};

If you like/prefer you can instead do this conversion in the action creators:

onDatesChange = ({ startDate, endDate }) => {
  this.props.dispatch(setStartDate(startDate));
  this.props.dispatch(setEndDate(endDate));
};
export const setStartDate = (startDate) => ({
  type: "setStartDate",
  startDate: startDate.toISOString(true),
});

export const setEndDate = (endDate) => ({
  type: "setEndDate",
  endDate: endDate.toISOString(true),
});
Drew Reese
  • 165,259
  • 14
  • 153
  • 181