简体   繁体   English

带有 useSelector 的 useEffect 钩子的无限循环

[英]Infinite loop with useEffect hook with useSelector

I have a normalized Redux store in my React Native application.我的 React Native 应用程序中有一个标准化的 Redux 存储。

The structure of my reducer is:我的减速机的结构是:

{
  byId: {},
  allIds: []
}

In my component, I get the slice of Redux state using the useSelector hook:在我的组件中,我使用useSelector钩子获取 Redux 状态的useSelector

const categories = useSelector((state: AppState) =>
  state.products.allIds.map((id) => state.categories.byId[id.toString()])
);

The logic in the useSelector just converts the byId object into an array. useSelector的逻辑只是将byId对象转换为数组。

The infinite looping occurs when I set the categories array as a dependency:当我将categories数组设置为依赖项时,会发生无限循环:

const [values, setValues] = useState<any[]>([]);

useEffect(() => {
  setValues([{ id: 1 }]);
  console.log("logging");
}, [categories]);

Not sure what is the problem.不知道是什么问题。 I believe it's the useSelector logic that converts the objects into an array.我相信是useSelector逻辑将对象转换为数组。

EDIT:编辑:

Full component code:完整的组件代码:

// React
import React, { useEffect, useState } from "react";

// React redux
import { useSelector } from "react-redux";
import { AppState } from "@reducers/rootReducer";

// Logic
import ProductsScreenLogic from "./ProductsScreen.logic";

// Common components
import ScreenView from "@common/screen/Screen.view";

// Components
import NewProductModalView from "@components/products/new-product-modal/NewProductModal.view";
import ProductsTabsView from "@components/products/products-tabs/ProductsTabs.view";
import ProductListView from "@components/products/products-list/ProductList.view";
import CategoryListView from "@components/products/category-list/CategoryList.view";

const ProductsScreenView: React.FC = () => {
  const { displayProductList, setDisplayProductList, products } =
    ProductsScreenLogic();


  // Makes the categories ById object into an array of categories
  const categories = useSelector((state: AppState) => state.categories.allIds.map((id) => state.categories.byId[id.toString()])
  );


  const [values, setValues] = useState<any[]>([]);

  useEffect(() => {
    setValues([{ id: 1 }]);
    console.log("logging");
  }, [categories]);

  return (
    <>
      <NewProductModalView />
      <ScreenView></ScreenView>
    </>
  );
};

export default ProductsScreenView;

In useEffect you update the state , witch cause render , render call useSelector witch every time return new array for useEffect , witch cause update the state.在 useEffect 中,您更新状态,导致渲染,每次渲染调用 useSelector 为 useEffect 返回新数组,导致更新状态。 To fix you can remove categories from useEffect dependency array要修复您可以从 useEffect 依赖项数组中删除类别

The problem is that your selector always returns a new reference (because of the call to map ).问题是你的选择器总是返回一个新的引用(因为调用了map )。 You could instead use createSelector which will memoize it and only return a new reference when something inside either allIds or byId changes:您可以改为使用createSelector ,它会记住它,并且仅在allIdsbyId发生更改时才返回新引用:

const selectAllCategories = createSelector(
    (state: AppState) => state.categories.allIds,
    (state: AppState) => state.categories.byId,
    (categoriesIds, categoriesById) => categoriesIds.map((id) => categoriesById[id.toString()])
);

But ideally you should avoid such selectors that go through the whole byId object, because it kind of negates the benefits of having a normalized state.但理想情况下,您应该避免使用遍历整个byId对象的此类选择器,因为它在byId否定了具有规范化状态的好处。 You should rather have a parent component that only selects state.categories.allIds , and then passes the ids as props to child components, and every child component will select its own state.categories.byId[id] .你应该有一个只选择state.categories.allIds的父组件,然后将 ids 作为道具传递给子组件,每个子组件都会选择自己的state.categories.byId[id] This way if a category changes, only the corresponding child component will rerender, instead of having the parent and all of the children rerender.这样,如果类别发生变化,则只有相应的子组件会重新渲染,而不是让父组件和所有子组件重新渲染。

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

相关问题 带有依赖项数组的 React Native 动画 useEffect 钩子创建无限循环 - React Native animation useEffect hook with dependencies array creates infinite loop 在 useEffect 钩子中设置状态和 AsyncStorage 会导致无限循环? - Setting state along with AsyncStorage in useEffect hook causes infinite loop? UseEffect 无限循环与 Firebase - UseEffect infinite loop with Firebase 为什么在添加 redux state 作为对“useEffect”挂钩的依赖项时会导致应用程序启动时出现无限循环? - Why infinite loop on app start is caused when adding a redux state as dependency to a `useEffect` hook? react-native:当 api 响应更新为 state 时,在 useEffect 挂钩调用上,它将无限数组 Z34D1F91FB2E514B896BZA8 到控制台打印到无限循环 - react-native: On useEffect hook call when api response is updated to state it'll go to infinite loop but infinite array is printing in console while 循环在 useEffect 钩子中不起作用 - while loop is not working in useEffect hook 反应本机钩子中的无限循环 - Infinite loop in react native hook react native stop useEffect() 无限循环 - react native stop useEffect() infinite loop 无限循环 - React Native useState useEffect - Infinite Loop - React Native useState useEffect useEffect 无限循环,即使使用空数组作为依赖项 - useEffect infinite loop even with empty array as dependency
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM