如何正确使用useEffect与数组依赖关系。我从redux商店传递了状态,但我的组件仍无限渲染

问题描述 投票:0回答:2

我正在使用useEffect钩子并使用函数getStoreUsers获取用户数据列表,该函数使用getStoreUsers函数调度响应并在redux存储中存储shopUsers(这是一个数组)。

在数组依赖中,我正在编写[shopUsers]。我不知道它为什么会导致无限渲染。

这是我如何使用useEffect钩子:

useEffect(() => {
    const { getStoreUsers, shopUsers } = props;
    setLoading(true);
    getStoreUsers().then(() => {
      setLoading(false);
    }).catch(() => {
      setLoading(false);
    });
  }, [shopUsers]);

我想只在shopUsers数组中的数据发生变化时才重新渲染组件。

如果我在数组依赖项中写shopUsers.length。它停止重新渲染。

但是,假设我有一个页面,当用户点击userList并在下一页上更新用户数据时,该页面会打开。更新后,我希望用户返回到之前未卸载的相同组件。因此,在这种情况下,数组长度保持不变,但更新数组索引中的数据。所以shopUsers.length在这种情况下不起作用。

javascript reactjs react-native redux react-hooks
2个回答
2
投票

你的效果是基于“shopUsers”道具触发的,它本身会触发一个redux动作来更新“shopUsers”道具,这也就是为什么它会无限制地发射。

我认为你想要优化的是组件本身的渲染,因为你已经在使用redux,我假设你的props / state是不可变的,所以你可以使用React.memo重新渲染你的组件道具改变。

你也应该在钩子之外定义你的state / props变量,因为它们在整个函数的范围内使用,就像这样。

在你的情况下,如果你将一个空数组作为第二个参数传递给memo,那么它只会触发ComponentDidMount,如果你传递null / undefined或者没有传递任何东西,它将在ComponentDidMount + ComponentDidUpdate上触发,如果你想优化的话即使在道具更改/组件更新时,除非特定变量发生变化,否则钩子不会触发,因此您可以添加一些变量作为第二个参数

React.memo(function(props){
  const [isLoading, setLoading] = useState(false);
  const { getStoreUsers, shopUsers } = props;
  useEffect(() => {
    setLoading(true);
    getStoreUsers().then(() => {
      setLoading(false);
    }).catch((err) => {
      setLoading(false);
    });
  }, []);
...
})

1
投票

您可以创建自定义挂钩来执行您想要的操作:

在此示例中,我们替换数组中的最后一个元素,并在控制台中查看输出。

import React, { useState, useEffect, useRef } from "react";
import ReactDOM from "react-dom";
import { isEqual } from "lodash";

const usePrevious = value => {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
};

const App = () => {
  const [arr, setArr] = useState([2, 4, 5]);
  const prevArr = usePrevious(arr);

  useEffect(() => {
    if (!isEqual(arr, prevArr)) {
      console.log(`array changed from ${prevArr} to ${arr}`);
    } 
  }, [prevArr]);

  const change = () => {
    const temp = [...arr];
    temp.pop();
    temp.push(6);
    setArr(temp);
  };

  return (
      <button onClick={change}>change last array element</button>
  )
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

实例here

© www.soinside.com 2019 - 2024. All rights reserved.