3

我将 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中使用该实例。render

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

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

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

有没有更好、更少的锅炉代码、更不可怕的方法?有什么建议么?


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

object SomeComp {
  trait Props{
    type T
    val t: T
    val onChange: T => Callback
  }

  // use Props#T if you need to reference T
  val component = ReactComponentB[Props]("SomeComp")...

  def apply[_T](_t: _T, _onChange: _T => Callback) = {
    val props = new Props {
      type T = _T
      val t = _t
      val onChange = _onChange
    }
    component(props)
  }
}
4

1 回答 1

3

多年来,我在多态组件上做了一些尝试,并放弃了完美。如果我们接受微小的缺陷,那么就有足够的,甚至是很好的解决方案:

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 → Callback),那么您可以使用一个内置的:https ://github.com/japgolly/scalajs-react/blob/master/doc/EXTRA .md#statesnapshot(文档适用于 1.0.0-RC1+,曾经是两个类:{Reusable,Exeternal}Var in pre-1.0 days)

于 2017-04-23T11:57:42.850 回答