React 从父道具克隆一个对象在重新渲染时不断更新

时间:2021-05-13 15:40:18

标签: javascript arrays reactjs react-props

不知道解决这个问题的方法是什么。我们从 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 过滤器类别。

查看附加的应用示例。

enter image description here enter image description here

我已将大部分文件转储到此处:https://codesandbox.io/s/charming-sinoussi-l2iwh?file=/data.js:0-2061 和示例数据。我不知道这有多大帮助,当有这么多依赖项时,很难做出一个有效的例子。

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

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

2 个答案:

答案 0 :(得分:0)

  1. useEffect 执行异步操作,因此 filterOffers 可以在渲染时未定义。

  2. 如果您想根据某个其他值创建一个值并希望对其进行优化,请使用 useMemo 钩子。

  3. 如果您想在组件的重新渲染之间存储一个值,请使用 useRef 钩子。

    const newFilters = useRef(JSON.parse(JSON.stringify(props.options))); // copy the object from props
    const filterOffers = useMemo(() => {
         filterOffers = newFilters.current.map((item: any) => {
             return { value: item.offerType, display: item.offerType };
         });
         console.log('filterOffers: ', filterOffers); // succesfully logs the filtered items. 
    }, [newFilters]);
    

答案 1 :(得分:0)

这就是你所需要的。如果遇到性能问题,请使用 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

相关问题