【问题标题】:reagent atom/component only re-renders once试剂原子/组件仅重新渲染一次
【发布时间】:2016-07-03 21:31:27
【问题描述】:

我创建了一个脚注系统,使用基于语义 ui(仅限 css)的试剂(对于任何阅读 javascript 的人来说,这是一个 clojurescript 包装器),它处理点击和键盘事件以及鼠标悬停。除了一件小事之外,一切都完美无缺:它只正确处理一次键盘事件,然后就失败了。

代码在底部,但有点复杂,所以我会在展示之前解释一下。

所有原子都是试剂原子。入口点是footnote,它是一个获取脚注文本以及页面标记(不相关)的组件。

footnote及其下游函数:

  1. 从全局状态中获取一个计数器值,将其递增,并将其用作脚注的数字,

  2. 创建一些局部状态(试剂原子)来控制包含文本的模态是否可见,并将其初始化为false,

  3. 将带有工具提示的上标脚注标识符附加到文本(用于鼠标悬停)

  4. 将点击事件处理程序附加到该脚注标识符,将模态可见性原子设置为 true,并且

  5. 将键盘事件监听器附加到全局窗口,当按下数字时,它将模态可见性原子设置为 true。

然后,当模态可见性原子为真时:

  1. 另一个键盘事件侦听器附加到全局窗口,它将模态可见性原子设置为 false。

  2. 一个点击监听器附加到模态本身(在一些地方,因为我对 DOM 很烂,不相信我有能力找出可能点击的位置),也可以设置模态可见性原子为假。

我认为应该发生的事情:

在渲染时,鼠标悬停应显示带有文本的工具提示,单击脚注编号或按键盘上的脚注编号应打开带有文本的模式。当模式打开时,单击任意位置应将其关闭,按任意键也应如此。关闭模式后,用户应该能够通过单击或按键盘上的数字再次打开它。

实际发生的情况:

除上一段中斜体字外的所有内容。相反,在关闭模式后,如果我按相应的键再次打开它,模式不会重新打开(单击仍然有效)。

当我包装密钥处理函数调试日志调用时,它会将“true”记录到控制台,表明原子处于预期状态。

有趣的是,通过点击刷新或重新渲染整个虚拟“页面”(即包含脚注组件的更高级别的组件 - 这是一个具有虚拟页面作为反应/试剂组件的单页面站点),或者仅仅通过渲染另一个包含不同/没有脚注的“页面”组件然后重新渲染原始的“页面”组件,似乎重置了我得到的任何一种不稳定的状态,并且键盘触发器再次工作。

与此相关的是,我在全局窗口上挂着其他键盘事件,但没有使用与脚注相同的击键。特别是,我有用于在“页面”之间导航的键盘事件(h 表示主页等)。有趣的是,如果我使用其他键之一关闭模式,它工作得很好——很可能是因为其他键首先重新渲染其他页面之一,然后根据我的强制重新渲染来渲染原始页面?

下面的代码(从我最初发布这个问题时修改)试图通过重新渲染原始页面(即navload)来利用最后一个怪癖,但没有骰子(可能是因为反应足够聪明,不会如果页面已经存在,则重新渲染页面?)。

我还尝试通过首先渲染一个虚拟页面然后立即再次渲染原始页面来强制在关闭函数中重新渲染,但没有骰子——这实际上使事情变得更糟(重新渲染不再重置键盘脚注容量。)

最后,我尝试在close-modal 中包含reagent/force-update-all 以及this issue 中的“强制”技巧。两者都没有导致行为发生任何变化。

其他可能相关的信息:

listen 函数来自 google 闭包库 (goog.events),而不是普通的 javascript。不知道这是否具有奇怪的语义或可能导致此问题的东西。

有人有什么绝妙的见解吗?谢谢! :-)

(defn footnote-flag [num ratom text]
  [:sup {:data-tooltip text
         :on-click #(reset! ratom true)}
         (str "(" num ") ")])

(defn close-modal [ratom page]
  (cond
    (= @ratom true)
    (do
      (reset! ratom false)
      (navload page))))

(defn modal-content [text ratom page]
  (when @ratom
    (do
      (listen js/window "keypress" #(close-modal ratom page))
      [:span.ui.dimmer.modals.page.transition.visible.active
       {:on-click #(close-modal ratom page)}
       [:span.ui.standard.basic.modal.transition.visible.active.scrolling
        {:on-click #(close-modal ratom page)}
        [:p text]]])))

(defn handle-footnote-key [key-event num page ratom]
  (let [keypress (.-keyCode key-event)]
    (cond
      (and  (= (+ 48 num) keypress) (= page @stdio.nav.curpage))
      (reset! ratom true))))

(def footnote-counter (atom 0))

(defn footnote [text page]
  (do
    (swap! footnote-counter inc)
    (let [modal-state (atom false)
          num @footnote-counter]
      (listen js/window "keypress" #(handle-footnote-key % num page modal-state))
      (fn [text]
        [:span
         [footnote-flag num modal-state text]
         [modal-content text modal-state page]]))))

【问题讨论】:

  • 我有 70% 左右的把握确定问题是 modal-contentfootnote 中的 listens 干扰。当它第一次渲染时,footnote 注册一个监听器以在某个按键上打开模式。然后当模态被注册时,它被设置为在任何按键上关闭模态。因此,在第一次呈现模态框后,您将打开和关闭模态框。我会查看create-class 以确保您正在创建和删除您的听众。
  • 我认为是对的。在偶然发现下面的解决方案之后,这真的更像是一个 JavaScript/dom 问题,而不是所有听众相互争斗的任何事情。我的猜测是,意外的解决方案通过重新挂起事件侦听器 (??) 重新渲染或其他什么来解决问题......
  • 我不知道您可以在 create-class 中删除侦听器。那可能会更干净!

标签: reactjs clojurescript semantic-ui reagent


【解决方案1】:

footnote-counterclojure.core/atom,什么时候应该是 reagent.core/atom

【讨论】:

  • 不,都是试剂原子(我只是提到了名字)
  • num @footnote-counter 移动到渲染中的 let fn
  • 这样? gist.github.com/paultopia/f299d3e41ee0a5ada462fbb85c757899 -- 不幸的是,这似乎打破了脚注编号(当我这样做时,由于某种神秘的原因,它们都呈现为 0)
  • 啊哈!但这给了我一个线索,一些四处寻找解决方案!添加我自己的答案,但也希望了解为什么...
  • 为了记录,我认为这应该是一个评论,而不是一个答案,迈克,虽然如果它是正确的,你可以让它成为一个答案。无论如何,这就是我的方法。 (此时,鉴于有一个讨论,我认为你不应该做任何事情。)
【解决方案2】:

经过一番摸索,并在上面 Mike Thompson 的提示的帮助下,出现了一个解决方案。

将键事件侦听器移动到返回的渲染函数而不是外部函数似乎会产生正确的行为。老实说,我不太清楚为什么,并且会喜欢任何见解......

(defn footnote [text page]
  (do
    (swap! footnote-counter inc)
    (let [modal-state (atom false)
          num @footnote-counter]
      (fn [text]
        (do
          (listen js/window "keypress" #(handle-footnote-key % num page modal-state))
         [:span
          [footnote-flag num modal-state text]
          [modal-content text modal-state page]])))))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-02
    • 2021-01-24
    • 1970-01-01
    • 2018-08-12
    • 2019-06-01
    • 2020-02-13
    相关资源
    最近更新 更多