以最封装的方式封装/封装ScalaJS react js组件(react stick)

Wrapping/facading a ScalaJS react js component (react-sticky) in the most encapsulating manner possible

本文关键字:封装 react js 组件 stick ScalaJS 方式      更新时间:2023-09-26

我见过几种在scala.js中制作facade或包装Javascript组件的方法,包括为react.js Components这样做。我想,它们封装或隐藏组件本身提供的功能的程度似乎各不相同,这取决于它们的需求(也许它们只需要调用一个方法)。

在我的情况下,我需要使用一个名为react-sticky的组件,我首先尝试确定如何为这里提供的仅有的两个组件类StickyContainer中的一个组件类制作facade。

我的问题如下:

  1. 如何在scala中处理static Javascript方法?我需要关心这个吗,或者我可以对此持不可知论态度吗
  2. 要在另一个componentrender()中只包含component而不包含任何Props,我需要最少多少"facade"
  3. 包装或封装reactjs组件与任何其他js本机类的根本区别是什么

最后,以下哪种策略最合适?

@js.native
trait StickyContainer extends js.Object { ... }
object StickyContainer extends StickyContainer {}

case class StickyContainer(offset: js.UndefOr[Double],...) {
    def apply() = { React.createElement(ReactUniversal.Image, JSMacro[StickyContainer](this), children: _*)
}

如何处理scala中的静态Javascript方法?我需要关心这个吗,或者我可以对此持不可知论态度吗?

当你想包装react组件时,你不需要担心它的底层实现

 @ScalaJSDefined
 class MyComponent extends ReactComponent {
  ...
}
val ctor = js.constructorOf[MyComponent]
ctor.childContextTypes = js.Dictionary("contextfield" -> React.PropTypes.`object`.isRequired)

如果你想知道scala.js中开箱即用的静态字段支持。。https://github.com/scala-js/scala-js/issues/1902

为了在另一个组件的render()中包含不带任何道具的组件,我需要制作的最小"facade"数量是多少?

global.ReactSticky = require('react-sticky') // load js lib
@js.native
object ReactSticky extends js.Object {
  val StickyContainer : js.Dynamic = js.native
  val Sticky : js.Dynamic = js.native
}
//Using JSMacro
case class StickyContainer(fields ..) {
  def apply(children : ReactNode*) = {
     val props  = JSMacro[StickyContainer](this)
     React.createElement(ReactSticky.StickyContainer,props,children :_*) 
   }
}
//Using FunctionMacro
def StickyContainer(fields ..)(children : ReactNode*) : ReactElement = {
     val props  = FunctionMacro()
     React.createElement(ReactSticky.StickyContainer,props,children :_*) 
   }
}

包装或封装reactjs组件与任何其他js本机类有什么根本不同?

如果你看到object ReactSticky extends js.Object ...,在书写门面方面没有什么不同。但在react世界中,你需要ReactElement,这就是你需要额外包装器来进行-React.createElement(classCtor,props,children)调用的地方。。

建议使用invariant来获得关于如何使基于SRI的组件工作的正确答案。其他基于japgolly的JS在处理第三方JS时并不那么友好。

以下是我如何获得库react-mt-svg-lines,一个动画库,正在工作:

喧闹声

case class MtSvgLines(
                      key: js.UndefOr[String] = js.undefined,
                      ref: js.UndefOr[String] = js.undefined,
                      animate: js.Any = true,
                      duration: Double = 10.0,
                      stagger: js.UndefOr[Double] = js.undefined,
                      timing: js.UndefOr[String] = js.undefined,
                      playback: js.UndefOr[String] = js.undefined,
                      fade: js.UndefOr[String] = js.undefined
                    )
{
  def apply(children: ReactNode*): ReactComponentU_ = {
    val props = JSMacro[MtSvgLines](this)
    val f = React.asInstanceOf[js.Dynamic].createFactory(js.Dynamic.global.SvgLines.default)
    if (children.isEmpty)
      f(props).asInstanceOf[ReactComponentU_]
    else if (children.size == 1)
      f(props, children.head).asInstanceOf[ReactComponentU_]
    else
      f(props, children.toJsArray).asInstanceOf[ReactComponentU_]
  }
}

值得注意的是,确保createFactory中的自变量是exportglobal.Whatever。考虑儿童在数字上的差异。对每个可选项使用js.UndefOr

客户

def render(S: State, C: PropsChildren) = {
  <.header(^.key := UUID.randomUUID().toString, Styles.Header_TextIsCentered, Styles.Header_BackgroundIsGrayBlue_WithWhiteText)(
    <.div(^.className := "container")(
      <.h1()("justin shin, tampa fl"),
      MtSvgLines(animate = true, duration = 500) {
        import japgolly.scalajs.react.vdom.svg.all._
        svg(SvgStyles.svg,
          defs(
            maskTag(id := "mask", x := "0", y := "0", width := "100%", height := "100%",
              rect(id := "alpha", x := "0", y := "0", width := "100%", height := "100%"),
              text(id := "title", x := "50%",y := "0", dy := "1.58em")("Justin", transform := "translate(50, 0)"),
              text(id := "title", x := "50%",y := "0", dy := "1.58em")("Tampa")
            )
          ),
          rect(id := "base", x := "0", y := "0", width := "100%", height := "100%"),
          path(stroke := "green", strokeWidth := "10", fill := "none", d := "M20.8,51c0,0,20.8,18.2,21.5,18.2c0.6,0,33.3-38.5,33.3-38.5"),
        )
      }
    )
  )
}