如何记住一个 React hooks 组件被卸载,从而避免状态变化?

How remember that a React hooks component is unmounted, so can avoid state changes?

使用基于 class 的旧 React.js 代码,我可以这样做,以记住组件已被卸载:

  componentWillUnmount: function() {
    this.isGone = true;
  },

  loadUsers: function() {
    Server.loadUsers(..., (response) => {
      if (this.isGone) return;
      ...
    });
  }

如何使用基于钩子的组件做同样的事情?

这是一个示例挂钩函数组件,我不确定如何记住它已被卸载,所以我可以 return 在调用任何 setSomeState:

之前
export const GroupMembers = React.createFactory(function(props) {

  const [membersOrNull, setMembers] = React.useState(null);
  let isGone = false;  // ? (se [222] below

  React.useEffect(() => {
    Server.listGroupMembers(someGroupId, (response) => {
     if (/* is unmounted ?? */) return;
     setMembers(response.members);
    });
    return () => { /* how remember is unmounted?
                      would isGone = true; work? */ };
  }, []);

  ...

  return ..., Button({ title: "Remove all members", onClick: () => {
    Server.removeAllMembers(someGroupId, () => {
     if (/* is unmounted ?? */) return;
     setMembers([]);
    });
  }});

我想我不能使用 const [isGone, setGone] = useState(false) 因为我不应该在卸载后尝试访问状态(读取 isGone)。而如果我 [222] 在函数内部添加一个本地 let isGone = false ,在我看来,在函数内部创建的各种回调,将引用不同的 "instances"这个局部变量,取决于创建不同回调的不同 GroupMembers(..) 调用?还是我错了,这行得通吗? — 也许我可以创建一个带有局部 let isGone = false 的外部包装函数,但是,这会添加另一个包装函数和缩进:- /

只使用通过闭包访问的局部变量

React.useEffect(() => {
  let isActual = true;
  Server.listGroupMembers(someGroupId, (response) => {
     if (!isActual) return;
     setMembers(response.members);
  });
  return () => {isActual = false;};
}, []);

在这种情况下,标志只会在卸载时更新。但在一般情况下(useEffect 有一些非空依赖项)它也会使用。因此,在顺序渲染的情况下,您可以确定您永远不会处理较旧的请求。

PS最通用的方法是尽可能取消请求。

由于您也在 useEffect 方法之外使用 isGone 标志,因此您可以使用 useRef 来存储像

这样的变量
export const GroupMembers = React.createFactory(function(props) {

  const [membersOrNull, setMembers] = React.useState(null);
  const isGone = useRef(false);  // ? (se [222] below

  React.useEffect(() => {
    Server.listGroupMembers(someGroupId, (response) => {
     if (isGone.current) return;
     setMembers(response.members);
    });
    return () => { 
       isGone.current = true;
    };
  }, []);

  ...

  return ..., Button({ title: "Remove all members", onClick: () => {
    Server.removeAllMembers(someGroupId, () => {
     if (isGone.current) return;
     setMembers([]);
    });
  }});

PS: A better way to handle such things is to cancel the request when you are leaving the page instead of waiting for the response only to neglect it.