ReactJS - Это хорошая практика - открывать модальные окна асинхронно в функции обратного вызова? - PullRequest
1 голос
/ 05 августа 2020

Краткая предыстория:

Мое приложение росло больше, и я добавлял все больше и больше модалов для различных действий пользователя

Примерно так:

export const App =() => {
    const [openModal, setOpenModal] = useState();

    return (
        <>
            <Modal1 isOpen={ openModal === "modal1" } />
            <Modal2 isOpen={ openModal === "modal2" } />
            <Modal3 isOpen={ openModal === "modal3" } />
            <Modal4 isOpen={ openModal === "modal4" } />
            ...
        </>
    );
};

Состояние управление становилось довольно трудным. Поэтому я подумал о лучшем решении и пришел к выводу, что, возможно, я смогу заставить его работать, как window.confirm() работает.

И я мог бы, но я не уверен, что это хорошее решение ... поэтому я решил опубликуйте этот вопрос.

Это мой подход:

const handleButtonClick = async () => {
    const newFileName = await openRenameDialog(fileName)

    if (newFileName !== fileName) {
      const confirmMessage = `Are you sure you want to rename the file ${fileName} to ${newFileName}?`;
  
      if (await openConfirm("Please confirm", confirmMessage)) {
         setFileName(newFileName)
         alert("File has been renamed")
      } else {
         alert("File was not renamed")
      }
    }
}

Преимущество этого подхода состоит в том, что он больше не нужен для обработки модального состояния в App Компоненте

Такие функции, как openConfirm() и openRenameDialog(), создаются с использованием функции с именем createOpenModal, которая работает следующим образом:

import ReactDOM from "react-dom";

export const createOpenModal = (
    render: (onClose: (data?: any) => void) => JSX.Element
) => {
    return new Promise<any>(res => {
        const element = document.createElement("div");

        const handleClose = (data: any) => {
            document.body.removeChild(element);
            res(data);
        };

    document.body.appendChild(element);
    ReactDOM.render(render(handleClose), element);
  });
};

Пример проекта с использованием некоторых диалогов FluentUI можно найти здесь:

https://codesandbox.io/s/proud-glade-b7eop

Это хорошая практика - делать это так, как я? Или есть лучший способ управлять многими модальными окнами?

РЕДАКТИРОВАТЬ 1

Я добавил новый пример в свой ящик с кодами https://codesandbox.io/s/proud-glade-b7eop

App2.tsx использует более реактивный подход к обработке состояния.

App1 против App2

И, как вы видите, App2 - это просто беспорядок по сравнению с App1. Поскольку мне требовалось несколько новых функций-обработчиков для выполнения sh одного и того же.

Но если App1 использует антишаблон React, напрямую манипулируя DOM, мне было интересно, как можно было бы улучшить подход в App2

1 Ответ

0 голосов
/ 05 августа 2020

Ваше решение - своего рода антипаттерн для реакции. Нет смысла использовать в реакции такие операторы, как document.createElement или document.removeChild, если у вас нет действительно веской причины. Я бы сказал go об этом иначе. Имейте один компонент <Modal />, который является оболочкой для всего, что отображается в модальном окне. Затем в этом компоненте вы можете управлять тем, что отображается в модальном окне, используя комбинацию состояния приложения и подкомпонентов. В качестве грубого наброска:

export const App =() => {
    const [modalContent, setModalContent] = useState();

    return (
        <>
            {modalContent && <Modal content={modalContent} setModalContent={setModalContent} />}
            ...
        </>
    );
};

Итак, да, ваше приложение все еще управляет состоянием модального окна. Думаю, это нормально. Затем ваш <Modal /> может управлять тем, что появляется внутри него:


export const Modal = ({ content, setModalContent }) => {

  const modals = {
    rename: <Rename setModalContent={setModalContent} />
    confirm: <Confirm setModalContent={setModalContent} />
  }

  return (

    <div className="modalWrapper">
      {modals[content]}
    </div>

  )

}

Итак, в общем смысле ваш App дает высокоуровневую картину того, что должен делать Modal (должен он должен быть открыт или нет, что он должен отображать), а Modal сам выполняет инструкции, заданные состоянием App.

OR Если вы хотите, чтобы ваш * Состояние 1019 * управляется внутри самого Modal, вы можете поместить состояние в Modal:

export const App =() => (
  <>
    <Modal />
    ...
  </>
);

export const Modal = () => {
  const [modalContent, setModalContent] = useState()

  const modals = {
    rename: <RenameDialog setModalContent={setModalContent} />
    confirm: <ConfirmDialog setModalContent={setModalContent }/>
  }

  return (
    {modalContent && modals[modalContent]}
  )

}

Тогда ваши кнопки могут влиять на обратный вызов setModalContent. Это просто вопрос или как вы хотите, чтобы все было организовано. Второй способ более аккуратный, но вам может понадобиться способ установить модальное содержимое извне любого из модальных подкомпонентов, и в этом случае вам понадобится setModalContent выше по цепочке, как в первом сценарии. Или, если приложение становится действительно большим, добавьте сокращение и избавьтесь от бурения опор. Просто несколько идей, с которыми можно поиграть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...