不要使用scalajs-react在Treeview中重新渲染兄弟姐妹

时间:2017-07-19 14:09:21

标签: scalajs-react

我用scalajs-react构建了一个简单的TreeView。每个节点都包含一个文本字段。

我在儿童1.1中写了一些文字:

https://github.com/microsoftgraph/msgraph-sdk-dotnet/blob/dev/docs/overview.md

现在,如果我在1.2下方添加新的子1,则文本会消失,因为节点1及其所有子节点都会重新呈现:

enter image description here

在此Javascript-Redux enter image description here中添加子项时,不会重新呈现兄弟节点。我怎样才能用scalajs-react实现这个目标?

请参阅下面的代码或TreeView上的最小示例项目。

case class Node(text: String, children: Vector[Node])

object TreeView {
  val childNode = Node("1.1", Vector())
  val parentNode = Node("1", Vector(childNode))

  val rootNode = ScalaComponent.builder[Unit]("Node")
    .initialState(parentNode)
    .renderBackend[NodeBackend].build

  class NodeBackend($ : BackendScope[Unit, Node]) {

    def addChild =
      $.modState(
        _.copy(children = $.state.runNow().children :+ Node("1.2", Vector())))

    def render(node: Node): VdomElement = {
      val children =
        if (node.children.nonEmpty)
          node.children.toVdomArray(child => {
            val childNode = ScalaComponent.builder[Unit]("Node")
              .initialState(child)
              .renderBackend[NodeBackend].build
            childNode.withKey(child.text)()
          })
        else EmptyVdom

      <.div(
        node.text, <.input(), <.button("Add child", ^.onClick --> addChild),
        children
      )
    }
  }

  def apply() = rootNode()

1 个答案:

答案 0 :(得分:2)

这更像是如何做到这一点:

case class Node(label: String, text: String, children: Vector[Node])

object TreeView {
  val childNode = Node("1.1", "", Vector.empty)
  val parentNode = Node("1", "", Vector(childNode))

  val NodeComponent = ScalaComponent.builder[Node]("Node")
    .initialStateFromProps(identity)
    .renderBackend[NodeBackend]
    .build

  class NodeBackend($: BackendScope[Node, Node]) {

    def addChild =
      $.modState(s =>
        s.copy(children = s.children :+ Node("1.2", "", Vector.empty)))

    val onTextChange: ReactEventFromInput => Callback =
      _.extract(_.target.value)(t => $.modState(_.copy(text = t)))

    def render(node: Node): VdomElement = {
      val children =
        node.children.toVdomArray(child =>
          NodeComponent.withKey(child.label)(child))

      val input =
        <.input.text(
          ^.value := node.text,
          ^.onChange ==> onTextChange)

      <.div(
        node.label, input, <.button("Add child", ^.onClick --> addChild),
        children
      )
    }
  }

  def root = NodeComponent(parentNode)
}

更改

  • 不要为每个节点创建一个新组件,创建同一组件的新实例。除了其他原因之外,React总会认为它有不同之处并重新绘制它,失去有状态组件的状态
  • 将值和onChange添加到输入中,以便React跟踪编辑器内容,否则编辑器更改似乎只能起作用,但React会在它感觉到时擦除它们。
  • 不要在回叫中调用.runNow() - 这是一个适用于边缘情况的逃生舱,应始终避免使用

那样做。这仍然让我感到担忧,因为你使用了有害的有状态组件,因为它们是大型可变变量的高级版本。您可能会发现React进行了错误的调用,并在某些情况下将您的状态抛出运行时。您可以以更安全的方式无国籍地实现相同的目标,请查看https://japgolly.github.io/scalajs-react/#examples/state-snapshot以了解其中一种方法。希望有所帮助。