繁体   English   中英

由于 Memoize,React 组件不会在状态更改时重新渲染

[英]React component not re-rendering on state change due to Memoize

我在 React 组件上使用 memoize-one,该组件基本上是一个带有可以过滤的行的表。

Memoize 非常适合过滤,但是当我想插入新行时,它不会显示在表格上,直到我重新加载页面或使用过滤器。

如果我检查状态,新行的数据就在其中,所以大概发生的事情是 memoize 不允许组件重新渲染,即使状态已更改。

有趣的是,Delete 函数可以工作,我可以通过从状态中删除其数据来删除一行,并且它将重新呈现以反映更改...

这是我认为相关的代码部分,但如果您想查看更多,请告诉我:

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...

我不知道这是否很明显,但有两个函数称为 filter:属于 memoize 的this.filterArray.prototype.filter()

我环顾四周,发现这些帖子说Memoize 可以被覆盖

如果您遇到了 UI 错误,只需从 myComparison 返回 false 以暂时覆盖记忆,强制刷新每次重新渲染并返回默认组件行为,这很简单。

但我不确定“从组件返回 false”是什么意思

这是将您的代码重构为惯用的 React Hooks 风格(自然干编码)。

请注意如何使用useMemo()以不修改状态的方式对角色成员进行过滤和排序; 那是因为它们总是可以从有状态数据中重新计算出来。 只要useMemo()的 deps 数组保持同步(有 ESLint 规则可以帮助解决这个问题),这应该不需要额外的重新渲染。 :)

同样,如果您使用useCallback (这是useMemo ),您需要保持它们的 deps 数组同步。 如果您不使用useCallback ,这些回调可能会导致重新渲染,因为它们的身份会在每次渲染时发生变化。

import React, { Component } from "react";
import moment from "moment";
import { getRoleMembersDetailed } from "../libs/permissions-manager-client-v1.0";

function filterRoleMembers(
  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;
  });
}

// TODO: maybe use lodash's `sortBy`?
function compareByAlias(a, b) {
  if (a.alias < b.alias) {
    return -1;
  }
  if (a.alias > b.alias) {
    return 1;
  }
  return 0;
}

async function fetchRoleMembers(roleAttributeName) {
  return getRoleMembersDetailed(roleAttributeName);
}

async function loadData(roleAttributeName) {
  const roleMembers = Object.values(
    await fetchRoleMembers(roleAttributeName),
  );
  roleMembers.forEach((e) => {
    e.alias = e.alias.toLowerCase();
  });

  // TODO - This logic should be replaced with an API call that describes the roleAttributes.
  let roleAttributes = Object.values(roleMembers);
  roleAttributes = Object.keys(roleAttributes[0]);
  return {
    roleMembers,
    roleAttributes,
  };
}

const RoleContainer = ({
  role,
  roleAttributeName,
  searchValue,
  searchCriterion,
  userCanEdit,
}) => {
  const [collapsed, setCollapsed] = React.useState(true);
  const [isLoading, setIsLoading] = React.useState(true);
  const [roleAttributes, setRoleAttributes] = React.useState([]);
  const [roleMembers, setRoleMembers] = React.useState([]);
  React.useEffect(() => {
    loadData(roleAttributeName).then(
      ({ roleMembers, roleAttributes }) => {
        setRoleAttributes(roleAttributes);
        setRoleMembers(roleMembers);
        setIsLoading(false);
      },
    );
  }, [roleAttributeName]);
  const createRoleMember = React.useCallback(
    (newRoleMembers) => {
      const updatedRoleMembers = roleMembers.concat(newRoleMembers);
      setRoleMembers(updatedRoleMembers);
    },
    [roleMembers],
  );
  const deleteRoleMember = React.useCallback(
    (alias) => {
      const updatedRoleMembers = roleMembers.filter(
        (member) => member.alias !== alias,
      );
      setRoleMembers(updatedRoleMembers);
    },
    [roleMembers],
  );
  const filteredRoleMembers = React.useMemo(
    () =>
      filterRoleMembers(roleMembers, searchValue, searchCriterion),
    [roleMembers, searchValue, searchCriterion],
  );
  const sortedRoleMembers = React.useMemo(
    () => [].concat(filteredRoleMembers).sort(compareByAlias),
    [filteredRoleMembers],
  );
  return <>{JSON.stringify(sortedRoleMembers)}</>;
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM