我将如何使用 Scala Js React 构建 Bootstrap React Modal

How would I build a Bootstrap React Modal using Scala Js React

我如何使用 Scala.js React 库从 React Bootstrap 库创建一个 Modal 组件?

模态框必须将状态 (show = true/false) 更改为 show/hide 对话框这一事实构成了解决方案 non-trivial。我通过将它包装在一个组件中来解决这个问题,该组件具有可以更改的布尔状态 - 当它需要 shown/hidden 时,我会更改效果不纯的状态。

另一个问题是,如果 Modal 具有需要更改状态的按钮,则它们的事件处理程序需要以某种方式访问​​此状态。我通过在创建时授予组件用户访问组件后端的权限解决了这个问题。

这是我对模态的实现:

class Modal(bs: BackendScope[Unit, Boolean], onHide: => Unit, children: Modal => Seq[ChildArg]) {

  def render(show: Boolean) = {
    val props = (new js.Object).asInstanceOf[Modal.Props]
    props.show = show
    props.onHide = () => {
        dismiss()
        onHide
    }

    Modal.component(props)(children(this): _*)
  }

  def dismiss() = {
    bs.withEffectsImpure.setState(false)
  }
}

object Modal {

  @JSImport("react-bootstrap", "Modal")
  @js.native
  object RawComponent extends js.Object

  @js.native
  trait Props extends js.Object {
    var show: Boolean = js.native
    var onHide: js.Function0[Unit] = js.native
  }

  val component = JsComponent[Props, Children.Varargs, Null](RawComponent)

  type Unmounted = Scala.Unmounted[Unit, Boolean, Modal]

  def apply(onHide: => Unit = Unit)(children: Modal => Seq[ChildArg]): Unmounted =   {
    val component = ScalaComponent.builder[Unit]("Modal")
    .initialState(true)
    .backend(new Modal(_, onHide, children))
    .renderBackend
    .build
    component()
  }
}

以及使用它的对话框对象:

object Dialog {
  object Response extends Enumeration {
    type Response = Value
    val OK, CANCEL = Value
  }

  import Response._

  def prompt(title: String, body: String, okText: String): Future[Response] = {

    // Add an element into which we render the dialog
    val element = dom.document.body.appendChild(div(id := "dialog").render).asInstanceOf[Element]

    // Create a promise of a return and a method to send it
    val p = Promise[Response]
    def respond(ret: Response) = {
        // Remove the containing element and return the response
        dom.document.body.removeChild(element)
        p.success(ret)
    }

    Modal(respond(Response.CANCEL)) { modal =>

        // Function to dismiss the dialog and respond
        def quit(ret: Response) = {
            modal.dismiss()
            respond(ret)
        }

        // Create the components for our Modal
        Seq(
            ModalHeader(true,
                ModalTitle(title)
            ),
            ModalBody(body),
            ModalFooter(
                Button(variant = "secondary", onClick = () => { quit(Response.CANCEL) })("Cancel"),
                Button(variant = "primary", onClick = () => { quit(Response.OK) })(okText)
            )
        )
    }.renderIntoDOM(element).backend

    p.future
  }
}