如何使用带有scalajs-react的类型参数化组件

时间:2017-04-22 12:41:59

标签: scala scala.js scalajs-react

我使用scalajs 0.6.15与scalajs-react 0.11.3和reactjs 15.4.2。

考虑一个组件SomeComp,其中Props的值的类型需要参数化。

由于在使用组件构建器时需要知道类型,因此我将组件包装在类中。

class SomeComp[T]() {
  case class Props(t: T, onChange: T => Callback)

  val component = ReactComponentB[Props]("SomeComp")...

  def apply(t: T, onChange:T => Callback) = component(Props(t, onChange))
}
这是有效的。问题是,除非SomeComp的用户首先创建SomeComp的实例并在父{q}}方法中使用此实例,否则每次重新呈现父组件都会重新装入组件。 / p>

我的黑客解决方案是避免这种情况:

render

有更好的,更少的锅炉代码,不那么糟糕的方式吗?有什么建议吗?

更新 在@ Golly之后(感谢您精心解答!)建议我发现第二个解决方案最优雅,并希望在此处发布完整性:

object SomeComp {
  val genericComp = SomeComp[Any]()

  def apply[T](t: T, onChange: T => Callback) = genericComp(
    t = t, 
    onChange = (a: Any) => onChange(a.asInstanceOf[T])
  )
}

1 个答案:

答案 0 :(得分:1)

多年来,我在多态组件上做了几次尝试,并且放弃了完美。如果我们接受轻微的不完善,那么就有足够的,甚至是好的解决方案:

1a)围绕建造者的类。正是你在第一个例子中所拥有的除了之外的一个重要区别:每个类型只创建一个类。为同一类型创建一个新类导致你看到的卸载/重新安装(因为React认为组件是不同的),就好像你这样做:

final class SomeComp[A] private[SomeComp] () {
  val component = ReactComponentB[Props]("SomeComp")...
}
object SomeComp {
  val Int = new SomeComp[Int]
  val String = new SomeComp[String]
}

如果您事先不知道类型,那也很好,只需为您的类型创建一次类,并将其放在被调用者的伴随对象中。每种类型都需要创建一个单例,但所有内容仍然很简单。

1b)与上面类似,除了使用函数而不是类。每个类型创建一次(每个被调用者可选)并重用。

2)我不推荐这个,但你可以使用存在类型而不是通用类型,特别是使类型参数成为类型成员。

class Props {
  type T
  val value: T
  val onChange: T => Callback
}

现在组件是单态的,但是你需要一些样板来很好地创建和使用Props类。

顺便说一句,如果您自己创建了一个(T x T→回调),那么您可以使用内置的一个:https://github.com/japgolly/scalajs-react/blob/master/doc/EXTRA.md#statesnapshot(doc for 1.0.0- RC1 +,曾经是两个类:{可重用,外部}在1.0天之前的变量}