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

时间:2019-07-09 10:00:44

标签: react-bootstrap scalajs-react

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

1 个答案:

答案 0 :(得分:0)

模态必须更改状态(显示= true / false)以显示/隐藏对话框这一事实使解决方案变得不平凡。我通过将其包装在具有可以更改的布尔状态的组件中来解决此问题,并且当需要显示/隐藏该状态时,我会更改状态并带有不纯的效果。

另一个问题是,如果Modal的按钮需要更改状态,则其事件处理程序需要以某种方式访问​​此状态。我通过为组件用户提供创建时访问组件后端的权限来解决此问题。

这是我对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()
  }
}

以及使用它的Dialog对象:

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
  }
}