ClojureScript Reagent 父组件不会将光标传递给子组件

ClojureScript Reagent Parent component won't pass cursor to child component

我正在尝试创建一个简单的动态 svg。其中一个视图框设置随着 window 尺寸的变化而更新。

为此,我定义了一个顶级组件,如下所示

(defn windowdim_comp
 []
 (with-let [wndcomp_state (atom {:text "Parent2Component"})
         resize_handler #(swap! wndcomp_state assoc
                         :height (.-innerHeight js/window)
                         :width (.-innerWidth js/window))
         mousemove_handler #(swap! wndcomp_state assoc
                                   :x (.-pageX %)
                                   :y (.-pageY %))
         _ (.addEventListener js/window "resize" resize_handler)
         _ (.addEventListener js/document "mousemove" mousemove_handler)
         _ (swap! wndcomp_state assoc :height (.-innerHeight js/window))
         _ (swap! wndcomp_state assoc :width (.-innerWidth js/window))]
[:div
 [:p "width : " (:width @wndcomp_state) " height : " (:height @wndcomp_state)]
 [:p "x : " (:x @wndcomp_state) " y : " (:y @wndcomp_state)]
 (svgrender (cursor wndcomp_state [:text :width :height]))
 ]
(finally
  (.removeEventListener js/window "resize" resize_handler)
  (.removeEventListener js/document "mousemove" mousemove_handler))))

此组件然后调用一个名为 svgrender 的子组件,其光标仅采用 :text :width & :height 值...定义如下:

(defn svgrender
 [parent_state]
  (with-let [svgstate (atom {:clicked false})
           mousedown_handler #(swap! svgstate assoc
                                     :clicked true)
           mouseup_handler #(swap! svgstate assoc
                                   :clicked false)]
    [:svg {:viewBox "0 0 500 500"
         :width 500
         :height 500
         :id "svgcontainer"
         :onMouseDown mousedown_handler
         :onMouseUp mouseup_handler}
      [:g {:id "layer1"}
       [:rect {:id "rect1"
            :width 500
            :height 500
            :x 0
            :y 0
            :style {:fill (if (:clicked @svgstate)
                            "#ff00ff"
                            "#00ffff")}}]
         [:text {:x 5
            :y 15
            :class "small"}
          (gstring/format "width : %s height : %s" (:width @parent_state) (:height @parent_state))]
         [:text {:x 5
            :y 35
            :class "small"}
          (gstring/format "Click status : %s" (:clicked @svgstate))]
         [:text {:x 5
            :y 55
            :class "small"}
          "Parent Text:  " (:text @parent_state)]]]
        (finally
          (.removeEventListener (.getElementById js/document "svgcontainer")
                          "onmousedown" mousedown_handler)
          (.removeEventListener (.getElementById js/document "svgcontainer")
                          "onmouseup" mouseup_handler))))

问题是无论我做什么,我都无法从 parent_state 中获取值以显示在子节点中....它们只是显示为空值

有人可以帮助我吗?我不知道我做错了什么!!

更新: 根据 Walton 的建议,我想出了一些变体

  1. 对具有完整父状态的组件的 Parens 调用已通过

    (svgrender wndcomp_state)

结果:失败

  1. 像原始代码一样用光标调用组件

    (svgrender (游标 wndcomp_state [:text :width :height]))

结果:失败

  1. 按照 Walton 的建议,Parens 调用带轨道的组件

    (svgrender (track #(select-keys @wndcomp_state [:text :width :height])))

结果:通过!!

  1. 对具有完整父状态的组件的方形调用已通过

    [svgrender wndcomp_state]

结果:通过!!

  1. 像原始代码一样用游标调用组件

    [svgrender(光标 wndcomp_state [:text :width :height])]

结果:失败

  1. 根据 Walton 的建议对带轨道的组件进行方形调用

    [svgrender (track #(select-keys @wndcomp_state [:text :width :height]))]

结果:通过!!

现在这太奇怪了....不是吗?虽然我接受沃尔顿的回答,但谁能解释为什么会这样?

cursor behaves like get-in, while the code above expects it to behave like select-keys. While you could make cursor behave like your want by passing in a function as the first argument (see the second example in it's documentation) you don't need to write the cursor, so your better off using track。类似于 (track #(select-keys @wndcomp_state [:text :width :height]))(未经测试)

就是说,在您的示例中,即使跟踪也太过分了,您真的不需要新的反应。您可以将原始原子传递给 child 组件,一切都会完美。这样做的缺点是,如果您的示例被简化并且您有其他属性比 :width:height 更频繁地更改,那么每次更改时都必须重新呈现 child。

即使是那个问题也可以在没有新反应的情况下解决。传入普通地图即可。因此,您只需使用 [svgrender (select-keys @wndcomp_state [:text :width :height])] 而不是 [svgrender (track #(select-keys @wndcomp_state [:text :width :height]))](注意:我也使用方括号代替 parens,请参阅 here)。当 wndcomp_state 更改时使用此方法 windowdim_comp 组件将是 re-rendered,这会导致它使用 [=15= 中的文本、宽度和高度调用 svgrender 组件].如果这些发生了变化,就像用新的 props 调用 React 组件一样,它会被重新渲染。如果他们没有使用最初呈现时使用的相同参数调用 svgrender。在那种情况下,试剂不会重新呈现它(使用方括号。使用 parens 它将始终重新呈现)。

相同的效果,但 Reagent/React 跟踪依赖性的工作较少。