首页 > 解决方案 > React 从父道具克隆对象在重新渲染时不断更新

问题描述

不知道修复是什么。我们从 API 中获取一组对象,并使用它在视图中创建数据。同时在一个子组件(过滤器)中,我想映射数据中的一个字段以创建我的过滤器类别。过滤器将使用参数从 API 调用新数据,并返回该数据并更新道具(我认为这是问题,因为这会使用过滤后的数据重新设置子组件以再次设置类别)。

我认为将数组放入 useEffect 会阻止它被更新。

这是我的过滤器组件中的当前 tsx:

const ExclusiveOffersFilters = (props: ExclusiveOffersFiltersProps): JSX.Element => {
  const newFilters = JSON.parse(JSON.stringify(props.options)); // copy the object from props
  let filterOffers;

  useEffect(() => {
    filterOffers = newFilters.map((item: any) => {
      return { value: item.offerType, display: item.offerType };
    });
    console.log('filterOffers: ', filterOffers); // succesfully logs the filtered items. 
  }, []);

  return (
    <tr>
      <th>
        <Filter
          options={filterOffers} // here filterOffers is undefined
          alignRight={props.alignRight}
          handleClick={props.handleFilterChange}
          multiSelect={props.multiSelect}
          selectedItems={props.selectedItems}
        />
      </th>
    </tr>
  );
};

我也尝试过 const newFilters = [...props.options];newFilters = props.options.slice(0)但这是同样的问题(智慧似乎是使用 JSON 解析/字符串化)。

在我的父组件中,我这样称呼孩子:

<ExclusiveOffersFilters handleFilterChange={props.handleFilterChange} options={props.options} />

如果我删除该useEffect函数并仅更新过滤器,它将起作用,但是在选择一个过滤器后,应用程序会更新 api 调用,只接收过滤后的数据,因此过滤器中只设置了一个类别。我需要防止。

我需要一种方法来获取原始类别并冻结它们以防止更新。

编辑

这是我们的示例数据:

const data = [
  {
    offerId: 1,
    partnerName: "Another offer 4",
    imageUrl:
      "https://www.auctsjpg-w263-h98-99382466814e33da0cfa3d5d2afd921c.jpg",
    description:
      "Save up to 10% on something. <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p> <p>Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p> <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>",
    header: "Save up to 10%",
    enabled: true,
    deleted: false,
    offerType: "Motoring"
  },
  {
    offerId: 0,
    partnerName: "Amazing offer 4",
    imageUrl: "https://www.cGen",
    description:
      "Save up to 20% off* your business insurance thanks to our partnership with<BR/> Churchill Expert. Simply visit the Churchill Expert web page and choose the<BR/> insurance product to suit your business.<BR/>     Churchill Expert will automatically apply the discount to your premium for the<BR/>duration of your policy.     <BR/><BR/>*Minimum premiums apply. Discount applies to NIG policies arranged by Churchill Expert <BR/>and underwritten by U K Insurance Limited.<BR/> Professional Indemnity excluded.",
    header: "Save up to 20% off",
    enabled: true,
    deleted: false,
    offerType: "Insurance"
  },
  {
    offerId: 190,
    partnerName: "Amazing offer 4",
    imageUrl: "https://www.ch.Code=ExpertGen",
    description:
      "Save up to 20% off* your business insurance thanks to our partnership with<BR/> Churchill Expert. Simply visit the Churchill Expert web page and choose the<BR/> insurance product to suit your business.<BR/>     Churchill Expert will automatically apply the discount to your premium for the<BR/>duration of your policy.     <BR/><BR/>*Minimum premiums apply. Discount applies to NIG policies arranged by Churchill Expert <BR/>and underwritten by U K Insurance Limited.<BR/> Professional Indemnity excluded.",
    header: "Save up to 20% off",
    enabled: true,
    deleted: true,
    offerType: "Insurance"
  }
];

export default data;

如果我们在 offerType = Motoring 上进行过滤,那么我们再次使用 Motoring 作为我们的过滤器调用我们的 api,这只会从上述数据中返回 1 条记录,但是现在我们的过滤器会更新并且只显示 1 个 Motoring 过滤器类别。

请参阅应用程序中的附加示例。

在此处输入图像描述 在此处输入图像描述

我已经在这里转储了大部分文件:https ://codesandbox.io/s/charming-sinoussi-l2iwh?file=/data.js:0-2061以及示例数据。我不知道这有多大帮助,当有这么多依赖项时,很难做出一个可行的例子。

父 index.tsx 处理所有 ajax api 调用并将数据传递到 props。ExclusiveOffersFilters.tsx 收到此信息并进行更新,这是我要停止的部分。正如@Adam 在评论中指出的那样,我们正在尝试解决这个问题,但我认为实际上父母很好,问题在于孩子。

我们确实想在应用程序的其他地方应用这个逻辑,所以性能会很好。我想知道我是否只需要不使用 props.options 并为此使用不同的道具?

标签: javascriptarraysreactjsreact-props

解决方案


这就是你所需要的。如果遇到性能问题,请使用useMemo. 如果您没有遇到性能问题,请不要做任何事情

const ExclusiveOffersFilters = (props: ExclusiveOffersFiltersProps): JSX.Element => {

  const filters = props.options.map((item) => ({
    value: item.offerType, 
    display: item.offerType
  }));

  return (
    <tr>
      <th>
        <Filter
          options={filters}
          alignRight={props.alignRight}
          handleClick={props.handleFilterChange}
          multiSelect={props.multiSelect}
          selectedItems={props.selectedItems}
        />
      </th>
    </tr>
  );
};

示例useMemo

 const filters = useMemo(() => props.options.map(....),[props.options]);

useMemo除非您绝对确定自己需要它,否则我无法承受足够的压力。


推荐阅读