父组件循环调用子组件,子组件循环调用孙子组件,孙子组件需要弹窗,Modal 的放置位置

152 阅读4分钟

在 React 中,父组件循环调用子组件,子组件循环调用孙子组件,孙子组件需要弹窗,Modal 的放置位置有几种常见的选择,每种方式都有其优缺点。

1. Modal 放在孙子组件中

Modal 直接放在孙子组件中是最直接的方式。这种方式的优点是逻辑集中,孙子组件完全封装了自己的行为,不需要父组件或子组件关心弹窗的实现。

示例代码:

jsx复制

// 孙子组件
const GrandChildComponent = ({ showModal, setShowModal }) => {
  return (
    <div>
      <button onClick={() => setShowModal(true)}>打开弹窗</button>
      <Modal
        title="弹窗标题"
        visible={showModal}
        onCancel={() => setShowModal(false)}
        onOk={() => setShowModal(false)}
      >
        <p>弹窗内容</p>
      </Modal>
    </div>
  );
};

// 子组件
const ChildComponent = ({ items }) => {
  return (
    <div>
      {items.map((item, index) => (
        <GrandChildComponent key={index} showModal={false} setShowModal={() => {}} />
      ))}
    </div>
  );
};

// 父组件
const ParentComponent = ({ data }) => {
  return (
    <div>
      {data.map((item, index) => (
        <ChildComponent key={index} items={item.children} />
      ))}
    </div>
  );
};

优点:

  1. 封装性好:孙子组件完全封装了自己的弹窗逻辑,不需要父组件或子组件关心。
  2. 代码清晰:逻辑集中,易于维护。

缺点:

  1. 重复代码:如果孙子组件多次使用,可能会导致重复的弹窗逻辑。
  2. 状态管理复杂:如果弹窗需要与父组件或子组件交互,状态管理可能会变得复杂。

2. Modal 放在子组件中

Modal 放在子组件中,由子组件统一管理弹窗逻辑。这种方式适用于孙子组件的弹窗逻辑较为相似,且不需要父组件直接干预的情况。

示例代码:

jsx复制

// 孙子组件
const GrandChildComponent = ({ showModal, setShowModal }) => {
  return (
    <div>
      <button onClick={() => setShowModal(true)}>打开弹窗</button>
    </div>
  );
};

// 子组件
const ChildComponent = ({ items }) => {
  const [showModal, setShowModal] = React.useState(false);

  return (
    <div>
      {items.map((item, index) => (
        <GrandChildComponent key={index} showModal={showModal} setShowModal={setShowModal} />
      ))}
      <Modal
        title="弹窗标题"
        visible={showModal}
        onCancel={() => setShowModal(false)}
        onOk={() => setShowModal(false)}
      >
        <p>弹窗内容</p>
      </Modal>
    </div>
  );
};

// 父组件
const ParentComponent = ({ data }) => {
  return (
    <div>
      {data.map((item, index) => (
        <ChildComponent key={index} items={item.children} />
      ))}
    </div>
  );
};

优点:

  1. 减少重复代码:子组件统一管理弹窗逻辑,避免了孙子组件中的重复代码。
  2. 逻辑集中:弹窗逻辑集中在子组件中,便于维护。

缺点:

  1. 状态管理复杂:如果孙子组件的弹窗逻辑差异较大,状态管理可能会变得复杂。
  2. 灵活性差:孙子组件的弹窗逻辑受到子组件的限制,不够灵活。

3. Modal 放在父组件中

Modal 放在父组件中,由父组件统一管理弹窗逻辑。这种方式适用于弹窗需要与父组件直接交互,或者弹窗逻辑较为复杂的情况。

示例代码:

jsx复制

// 孙子组件
const GrandChildComponent = ({ openModal }) => {
  return (
    <div>
      <button onClick={openModal}>打开弹窗</button>
    </div>
  );
};

// 子组件
const ChildComponent = ({ items, openModal }) => {
  return (
    <div>
      {items.map((item, index) => (
        <GrandChildComponent key={index} openModal={openModal} />
      ))}
    </div>
  );
};

// 父组件
const ParentComponent = ({ data }) => {
  const [showModal, setShowModal] = React.useState(false);

  const openModal = () => setShowModal(true);

  return (
    <div>
      {data.map((item, index) => (
        <ChildComponent key={index} items={item.children} openModal={openModal} />
      ))}
      <Modal
        title="弹窗标题"
        visible={showModal}
        onCancel={() => setShowModal(false)}
        onOk={() => setShowModal(false)}
      >
        <p>弹窗内容</p>
      </Modal>
    </div>
  );
};

优点:

  1. 集中管理:父组件统一管理弹窗逻辑,便于全局控制。
  2. 灵活性高:弹窗逻辑可以根据父组件的状态动态调整。

缺点:

  1. 代码分散:弹窗逻辑分散在多个组件中,维护成本较高。
  2. 性能问题:父组件的重新渲染可能会导致子组件和孙子组件的不必要渲染。

4. 使用 Context 或 Redux 管理弹窗状态

如果弹窗逻辑较为复杂,且需要在多个层级之间共享状态,可以使用 Context 或状态管理库(如 Redux)来管理弹窗的状态。

示例代码(使用 Context):

jsx复制

import React, { createContext, useContext, useState } from 'react';
import { Modal } from 'antd';

const ModalContext = createContext();

const ModalProvider = ({ children }) => {
  const [showModal, setShowModal] = useState(false);

  const openModal = () => setShowModal(true);
  const closeModal = () => setShowModal(false);

  return (
    <ModalContext.Provider value={{ openModal, closeModal }}>
      {children}
      <Modal
        title="弹窗标题"
        visible={showModal}
        onCancel={closeModal}
        onOk={closeModal}
      >
        <p>弹窗内容</p>
      </Modal>
    </ModalContext.Provider>
  );
};

const GrandChildComponent = () => {
  const { openModal } = useContext(ModalContext);
  return <button onClick={openModal}>打开弹窗</button>;
};

const ChildComponent = ({ items }) => {
  return (
    <div>
      {items.map((item, index) => (
        <GrandChildComponent key={index} />
      ))}
    </div>
  );
};

const ParentComponent = ({ data }) => {
  return (
    <ModalProvider>
      {data.map((item, index) => (
        <ChildComponent key={index} items={item.children} />
      ))}
    </ModalProvider>
  );
};

优点:

  1. 状态共享:通过 Context 或 Redux,可以在多个层级之间共享弹窗状态。
  2. 解耦:组件之间的耦合度降低,弹窗逻辑与组件逻辑分离。

缺点:

  1. 复杂度增加:引入 Context 或 Redux 会增加代码复杂度。
  2. 性能问题:如果状态管理不当,可能会导致性能问题。

总结

  • 如果弹窗逻辑简单且只与孙子组件相关,可以将 Modal 放在孙子组件中。
  • 如果弹窗逻辑在子组件中较为通用,可以将 Modal 放在子组件中。
  • 如果弹窗需要与父组件交互或逻辑复杂,可以将 Modal 放在父组件中。
  • 如果弹窗状态需要在多个层级之间共享,可以使用 Context 或 Redux 管理状态。