如何卸载 React 函数式组件?

7

我已经建立了几个弹窗作为React函数组件。它们通过与弹窗关联的上下文中的isModalOpen布尔属性显示/隐藏。这很好用。

现在,由于种种原因,我的同事需要我重构这段代码并在更高层次上控制弹窗的可见性。以下是一些示例代码:

import React, { useState } from 'react';
import Button from 'react-bootstrap/Button';
import { UsersProvider } from '../../../contexts/UsersContext';
import AddUsers from './AddUsers';

const AddUsersLauncher = () => {
  const [showModal, setShowModal] = useState(false);

  return (
    <div>
      <UsersProvider>
        <Button onClick={() => setShowModal(true)}>Add Users</Button>
        {showModal && <AddUsers />}
      </UsersProvider>
    </div>
  );
};

export default AddUsersLauncher;

这一开始都很顺利。按钮被渲染出来,当按下按钮时模态框就会显示。

问题在于如何隐藏它。之前我只是在 reducer 中将 isModalOpen 设置为 false。

今天早些时候我与同事简短交谈时,他说上面的代码会起作用,我不需要传递任何东西到 AddUsers 中。不过我认为我需要将 setShowModal 函数传递到组件中,因为这样可以调用它来隐藏模态框。

但我也可能没有看到更简单的方法。有可能有吗?

3个回答

16

要在组件卸载时调用某些内容,可以使用useEffect。无论您在useEffect中返回什么,都将在组件卸载时被调用。例如,在您的情况下:

const AddUsersLauncher = () => {
  const [showModal, setShowModal] = useState(false);


  useEffect(() => {
    return () => {
      // Your code you want to run on unmount.
    };
  }, []); 


  return (
    <div>
      <UsersProvider>
        <Button onClick={() => setShowModal(true)}>Add Users</Button>
        {showModal && <AddUsers />}
      </UsersProvider>
    </div>
  );
};

useEffect的第二个参数接受一个数组,它会比较数组中元素的值以确定是否再次调用useEffect。在这里,我传递了空数组[],所以它只会调用一次useEffect。

如果你传递了其他内容,比如说,在数组中添加了showModal,那么每当showModal的值发生变化时,useEffect都会被调用,并且如果指定了返回函数,则会调用该函数。


谢谢您。我知道在 useEffect 中使用 return 作为清理函数。但是我的同事坚持认为不需要传递任何内容到 <AddUsers />,就可以从子组件中关闭它。我无法找到这样做的方法,这就是为什么我发布了这个问题。 - robertwerner_sf

1
如果您想在AddUsersLauncher中将showModal保留为状态变量,并从AddUsers内部更改它,则需要将setShowModal的引用传递给AddUsers。在React中进行状态管理可以变得混乱,因此我建议您查看Redux以存储和更改多个组件共享的状态。

谢谢。你关于需要将setShowModal传递到AddUsers中的想法与我的想法相吻合,但我的同事坚持认为这并不必要。今天早上他来了我会问他这个问题。至于Redux,我们决定在这个项目中不使用它,而是使用React上下文。到目前为止,我们发现这种替代状态管理方法没有问题。 - robertwerner_sf
P.S. 我又和同事谈了一下这个问题。他只是没有想到我们最终需要关闭模态框。 - robertwerner_sf

0

使用React 18,组件在开发模式下会被挂载两次,以测试其稳定性。

我们在挂载和卸载时编写的逻辑应该遵循这个范式。

useMount

import { useEffect, useRef } from "react";

function useMount(run: () => void) {
  const referencedRun = useRef(run);
  useEffect(() => {
    referencedRun.current();
  }, []);
}

export default useMount;

useUnMount

import React, {
  DependencyList,
  EffectCallback,
  useEffect,
  useRef
} from "react";
import useMount from "./useMount";

const useUnMount = (effect: EffectCallback, dependencies?: DependencyList) => {
  const unMounted = useRef(false);

  // with react 18 component will be mounted twice in dev mode, so setting the reference to false on the second mount
  useMount(() => {
    unMounted.current = false;
  });

  // to identify unmount
  useEffect(
    () => () => {
      unMounted.current = true;
    },
    []
  );

  // wrap dependencies with the callback
  useEffect(
    () => () => {
      if (unMounted.current) {
        effect();
      }
    },
    [dependencies, effect]
  );
};

export default useUnMount;

使用方法

  const [val, setVal] = useState("");

  useMount(() => {
    console.log("on mount...", val);
  });

  useUnMount(() => {
    console.log("on unmount...", val);
  }, [val]);

注意,在卸载时我们传递依赖项以解析最新的值。
参考:react-hooks-useeffect-cleanup-for-only-componentwillunmount

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接