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 的建议,我想出了一些变体
对具有完整父状态的组件的 Parens 调用已通过
(svgrender wndcomp_state)
结果:失败
像原始代码一样用光标调用组件
(svgrender (游标 wndcomp_state [:text :width :height]))
结果:失败
按照 Walton 的建议,Parens 调用带轨道的组件
(svgrender (track #(select-keys @wndcomp_state [:text :width :height])))
结果:通过!!
对具有完整父状态的组件的方形调用已通过
[svgrender wndcomp_state]
结果:通过!!
像原始代码一样用游标调用组件
[svgrender(光标 wndcomp_state [:text :width :height])]
结果:失败
根据 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 跟踪依赖性的工作较少。
我正在尝试创建一个简单的动态 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 的建议,我想出了一些变体
对具有完整父状态的组件的 Parens 调用已通过
(svgrender wndcomp_state)
结果:失败
像原始代码一样用光标调用组件
(svgrender (游标 wndcomp_state [:text :width :height]))
结果:失败
按照 Walton 的建议,Parens 调用带轨道的组件
(svgrender (track #(select-keys @wndcomp_state [:text :width :height])))
结果:通过!!
对具有完整父状态的组件的方形调用已通过
[svgrender wndcomp_state]
结果:通过!!
像原始代码一样用游标调用组件
[svgrender(光标 wndcomp_state [:text :width :height])]
结果:失败
根据 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 跟踪依赖性的工作较少。