I'm using memoize-one on a React component that is basically a table with a rows that can be filtered.
Memoize works great for the filtering but when I want to insert a new row, it won't show up on the table until I either reload the page or use the filter.
If I check the state, the new row's data is in it, so presumably what is happening is that memoize is not allowing the component to re-render even if the state has changed.
Something interesting is that the Delete function works, I am able to delete a row by removing its data from the state and it will re-render to reflect the changes...
Here's the part of the code I consider relevant but if you would like to see more, let me know:
import React, { Component } from "react";
import memoize from "memoize-one";
import moment from "moment";
import {
Alert,
Card,
Accordion,
Button,
Table,
Spinner,
} from "react-bootstrap";
import PropTypes from "prop-types";
import { getRoleMembersDetailed } from "../libs/permissions-manager-client-v1.0";
import RoleMember from "./RoleMember";
import CreateMemberModal from "./CreateMemberModal";
class RoleContainer extends Component {
filter = memoize((roleMembers, searchValue, searchCriterion) => {
const searchBy = searchCriterion || "alias";
return roleMembers.filter((item) => {
if (item[searchBy]) {
if (searchValue === "") {
return true;
}
const value = searchValue.toLowerCase();
if (searchBy !== "timestamp") {
const target = item[searchBy].toLowerCase();
return target.includes(value);
}
// Case for timestamp
const target = moment(Number(item[searchBy]))
.format("MMM DD, YYYY")
.toLowerCase();
return target.includes(value);
}
return false;
});
});
constructor(props) {
super(props);
this.state = {
collapsed: true,
roleAttributes: [],
roleMembers: [],
isLoading: true,
};
}
componentDidMount = async () => {
const roleMembers = Object.values(await this.fetchRoleMembers());
roleMembers.forEach((e) => {
e.alias = e.alias.toLowerCase();
return null;
});
roleMembers.sort((a, b) => {
if (a.alias < b.alias) {
return -1;
}
if (a.alias > b.alias) {
return 1;
}
return 0;
});
// TODO - This logic should be replaced with an API call that describes the roleAttributes.
let roleAttributes = Object.values(roleMembers);
roleAttributes = Object.keys(roleAttributes[0]);
this.setState({
roleMembers,
roleAttributes,
isLoading: false,
});
};
fetchRoleMembers = async () => {
const { roleAttributeName } = this.props;
return getRoleMembersDetailed(roleAttributeName);
};
createRoleMember = (newRoleMembers) => {
const { roleMembers } = this.state;
newRoleMembers.forEach((e) => {
roleMembers.push(e);
});
this.setState(
() => {
roleMembers.sort((a, b) => {
if (a.alias < b.alias) {
return -1;
}
if (a.alias > b.alias) {
return 1;
}
return 0;
});
return { roleMembers };
},
() => {
console.log("sss", this.state);
}
);
};
deleteRoleMember = (alias) => {
this.setState((prevState) => {
const { roleMembers } = prevState;
return {
roleMembers: roleMembers.filter((member) => member.alias !== alias),
};
});
};
render() {
const {
role,
roleAttributeName,
searchValue,
searchCriterion,
userCanEdit,
} = this.props;
const { collapsed, isLoading, roleAttributes, roleMembers } =
this.state;
const filteredRoleMembers = this.filter(
roleMembers,
searchValue,
searchCriterion
);
return (
// continues...
I don't know if it's obvious but there are two functions called filter: this.filter that belongs to memoize and Array.prototype.filter().
I did look around and found these post that says Memoize can be overridden:
If you’ve ran into a UI bug, it is simple to just return false from myComparison to temporarily override the memoization, forcing a refresh on every re-render and returning to the default component behaviour.
But I'm not sure what they mean with "return false from component"
useMemo!), if that's an option...