如何创建一个 async/await 函数来在 React 中显示对话框?

Bri*_*rns 8 javascript reactjs

我有一个使用react-modal的应用程序,它会弹出一个对话框,但是您必须将对话框组件嵌入到父窗体中,并且代码分散在父组件周围。

所以我想将所有对话框代码放在一个单独的文件中,并通过 async/await 调用显示它。

用户可以单击按钮打开对话框,输入值,单击“确定”,然后将某些内容写入数据库 - 例如

async function clickItem() {
  const ret = await getValue(initialValue)
  if (ret.ok) {
    // ret.value has new value - update db etc
  } else {
    // user hit cancel
  }
}
Run Code Online (Sandbox Code Playgroud)

一些要求 -

  • 将对话框编写为函数组件,使用 useState 挂钩等,因此可以完全动态
  • 将初始字段值传递给包装函数
  • 包装函数返回一个用对象解析的承诺 {ok:true/false, 相关字段值...}
  • 将对话框代码封装在一个文件中
  • 不需要像react-modal那样将组件嵌入到父组件中 - 只需调用 fn 即可将其渲染并插入到 DOM 中
  • 使用 jest 和/或 cypress 的可测试组件

有一个项目react-confirm-alert,它几乎可以实现我想要的功能,但是您不能将useState与它一起使用,也不能向它传递React组件,因此仅限于静态对话框。

那么你会如何去做这样的事情呢?

Bri*_*rns 7

我最终得到了一个没有样式的简单版本 - 这是一个代码沙箱 - https://codesandbox.io/s/react-async-dialog-3xdx7

对话

包装函数只是创建一个 Promise 并将回调传递resolve给对话框组件,当用户点击“确定”或“取消”时,对话框组件会调用“解析”。

如果将所有内容放入一个文件中,则看起来像这样 -

import React from "react";
import ReactDOM from "react-dom";

function App() {
  async function clickGetValue() {
    const ret = await getValue(3);
    console.log(ret);
  }
  return (
    <div className="App">
      <button onClick={clickGetValue}>Get Value</button>
    </div>
  );
}

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


function GetValue({ resolve, initialValue = 0 }) {
  const [value, setValue] = React.useState(initialValue);
  function clickPlus() {
    setValue(value => value + 1);
  }
  function clickMinus() {
    setValue(value => value - 1);
  }
  function clickOK() {
    removeDialog();
    resolve({ ok: true, value });
  }
  function clickCancel() {
    removeDialog();
    resolve({ ok: false });
  }
  return (
    <div id="getValue">
      <span id="getValue-value">{value}</span>
      <button onClick={clickPlus}>+1</button>
      <button onClick={clickMinus}>-1</button>
      <button onClick={clickOK}>OK</button>
      <button onClick={clickCancel}>Cancel</button>
    </div>
  );
}

export default function getValue(initialValue) {
  return new Promise((resolve, reject) => {
    addDialog(initialValue, resolve);
  });
}

function addDialog(initialValue, resolve) {
  const body = document.getElementsByTagName("body")[0];
  const div = document.createElement("div");
  div.setAttribute("id", "getValue-container");
  body.appendChild(div);
  ReactDOM.render(
    <GetValue initialValue={initialValue} resolve={resolve} />,
    div
  );
}

function removeDialog() {
  const div = document.getElementById("getValue-container");
  const body = document.getElementsByTagName("body")[0];
  body.removeChild(div);
}
Run Code Online (Sandbox Code Playgroud)