零到OM-第3幕

在第三篇文章中,我们将了解应用程序是如何初始化和呈现的。源代码位于github.

注:我强烈建议阅读上岗首先,如果你还没有这样做。

为了提高理解力,我们将跳过这两个文件,而不是从上到下浏览它们。


国家

大多数应用程序,至少有趣的是,有某种状态。在我们的例子中,我们存储两个数据点:

  • 托多的集合
  • 视图过滤器(即“全部”“有效”或“已完成”)。

关于OM,令人兴奋的是我们把所有的州都放在一个地方:

(def-app-state(atom:show:all:todos[])))

符号应用程序状态绑定到原子地图:视图过滤器(显示)设置为“全部”,并且托多斯是空集合。

如你所见,地图可以用大括号定义:KE1 VAL1…基恩山谷很高兴知道:元素数量不均匀会导致编译器错误)。可选地,你可以设定一个因为在clojurescript中逗号被视为空白,所以在对之间。

原子是所谓的参考值,这意味着它基本上指向不可变的数据。为什么我们不能使用一个简单的符号,让它在更改后指向新的数据?好,安原子能够在更改观察者的值时注册观察者交换!(或)重置!)OM利用此功能在状态更改时重新呈现组件。

通过将所有应用程序状态推送到系统边缘,其余的代码保持功能,因为现在只有一个可变对象。将状态放在一个特定的位置可以降低复杂性,因此更容易推理。

现在我们第一次见面!最后,呵呵?所以首先我们需要加载它:

(ns todomvc.app(:require[om.core:as om:include macros true][om.dom:as dom:include macros true][…])

宏-因为它们是一种特殊的函数-不能用标准加载要求但通过需要宏.然而,如果宏与本例中的宏在同一命名空间中,则添加:包含宏为真有同样的效果。

要启动应用程序,我们需要使用该功能OM/根告诉它

  • (a)提供什么,
  • (b)我们的国家是什么,
  • (c)以及连接到DOM的位置。
(om/root todo-app;;(a)应用程序状态;(b):目标(.getelementbyid js/document“todoapp”);(c)

OM会从这里拿走的。它启动一个呈现循环,当状态更改时,它将在单个批处理中更新组件。(非常通过利用浏览器的请求动画框架

现在我们来讨论一个棘手的问题:什么是todoapp

组件“todo app”

todoapp是一个接受两个参数的函数:状态和底层的react组件主人(OM为您创建)。

(defn todo app[:keys[todos]:as state owner];……)

您可能想知道为什么第一个参数看起来这么奇怪。这是Clojurescript在工作中的强大功能:破坏.它基本上允许您将符号绑定到数据结构的某些部分。在这种情况下[钥匙]是的快捷方式[托多斯:托多斯]-两者都绑定键的值托多斯从状态到符号托多斯.这个作为是可选的,允许为整个结构定义别名,状态在这种情况下。如果你想了解更多,我推荐阅读Clojure:破坏.

让我们来看看这个函数的主体:

(defn todo app[:keys[todos]:as state owner](reify om/irender(render[];创建DOM元素…)

你会注意到的第一件事是使化.它计算为实现所有指定协议的新对象。协议是“命名方法及其签名的命名集”。

这里OM/Irand实现了协议。它有一个提供函数,显然,它将组件呈现为HTML。当它检测到组件状态的变化时,它就会被OM调用。注:第一个参数是组件本身的实例,它被忽略了γ因为它是不需要的。

OM中有几个协议或多或少直接映射到React的生命周期步骤:

基本上有:

  • 可用于进行初始化工作的创建阶段(“出生”),
  • 更新阶段以响应状态更改并呈现组件,
  • 以及清理阶段(“死亡”)。

您永远不应该尝试实现的唯一协议是IsUrdUpDebug因为这正是OM真正闪耀的地方:它对旧状态和新状态进行比较,以决定是否重新呈现组件。而且,由于clojurescript中的数据结构是不可变的,所以只需要一个简单的相等性检查——与react昂贵的逐段比较相比,这是非常快的。这就是OM目前在基准测试中粉碎纯react.js应用程序的主要原因。

让我们回到提供以上功能:

(dom/div nil(header)(dom/input js:id“new todo”:ref“newfield”:placeholder“需要做什么?”:onkeydown(输入新的todo%state owner))(列出状态)(页脚状态)()))

它在OM的帮助下创建了真正的DOM元素奥姆多姆以前导入的命名空间。这些dom函数直接映射到react的dom api,意思是DOM/DIV变成反应器具有相同的参数:

  • 道具,修改组件输出/行为的javascript对象
  • 所有其他(可选)参数都是子组件

在这种情况下,根元素有四个子元素:输入字段和头,一个列表和一个页脚-只有三个函数。正如你所看到的,在没有道具的情况下使用。

让我们仔细看看文本输入:

(dom/input js:id“new todo”:placeholder“需要做什么?”:onkeydown(输入新的todo%状态所有者)

正如我们以前看到的,道具设置一个身份证件占位符将呈现为HTML标记属性的值。键控下注册在用户按下键后激发的事件处理程序-调用进入新的待办事项随着事件的发生,状态主人.

注: (…)是一个函数显式声明.基本上是一个简短的版本(fn[evt](输入新的todo evt状态所有者).所以%是函数的第一个参数,% 2第二个等等。

回到提供从上面看,功能页眉页脚不是特别有趣-让我们看看上市而是:

(defn listing[:keys[todos showing editing]:as state](dom/section js:id“main”:样式(hidden(empty?)todos))(dom/input js:id“toggle all”:type“checkbox”:onchange(toggle all%state):选中(每隔?:已完成的TODOS))(应用dom/ul js:id“TODO列表”(列出显示编辑的TODOS项)))

待办事项列表包装在

用身份证 主要的.当没有待办事项时,它是隐藏的(通过使用 隐藏的我们上次看到的效用函数)。在内部,我们找到一个复选框,只有当每个待办事项都标记为“已完成”时才会选中该复选框。在更改时,它调用 切换全部事件处理程序。此外,一个
    元素被创建并呈现它从 列表项功能。

    注:这个应用函数(与相应的javascript函数类似)是转换组件序列所必需的列表项到的单个函数参数DOM/UL.

    (defn list items[todos showing editing](om/build all item/todo item todos:key:id:fn(fn[todo](cond->todo((:id todo)editing)(assoc:editing true)(不可见?todo showing))(assoc:hidden true))))

    列表项使用OM全部建立函数创建组件序列,在这种情况下待办事项.第二个参数是每个组件接收的状态序列,这里是托多斯.第三个参数是选项图:

    • 关键是一个关键字,用于在状态中查找将用作反应键的值(身份证件在我们的例子中。这使得渲染更有效因为在重新呈现时,react知道哪个dom节点属于哪个sequence元素。
    • FN是一个在呈现前应用于状态的函数。所使用的函数使用了时髦的外观康德>螺纹表达式托多通过给定的形式对。首先,它添加了标志编辑到当前正在编辑的ID相同的任何TODO(如果有)。其次,它添加了标志隐藏的如果项的完成状态与显示视图过滤器(使用实用程序功能可见的?

    现在,让我们看看待办事项组件。

    组件“todo item”

    (defn todo item[todo owner](reify om/iinitstate(init state[]:编辑文本(:title todo))om/irenderstate(呈现状态[状态](let[类(cond->“”(:completed todo)(str“completed”)(:编辑todo)(str“编辑”))](dom/li js:类名类:样式(hidden(:hidden todo))(dom/div js:classname“view”(dom/input js:classname“toggle”:type“checkbox”:checked(and(:completed todo)“checked”):onchange(complete todo))(dom/label js:ondoubleclick(edit%todo owner)(:title todo))(dom/button js:classname“destroy”:onclick(destroy todo))(dom/input js:classname“edit”:value(om/get state owner:edit text):onblur(submit%todo owner):onchange(change%todo owner):onkeydown(key down%todo owner)(todo owner)))))

    这看起来相当复杂,但实际上相当简单。这个提供铁状态有一个附加参数与熨斗国家。它创造了一个带两个孩子的标签:一个DIV第二种观点和文本输入编辑编辑.取决于-它是由康德>-其中一个显示。

    在视图分区A复选框内(将项目标记为已完成),添加标签(显示TODO)和按钮(销毁TODO)。声明的事件处理程序基本上是不言而喻的。

    该组件还实现因尼特协议:初始化状态返回包含组件的初始化本地状态的映射。这与全局或传入状态不同,因为它通常只是暂时的,部件特定信息。在文本输入中,您可以看到它正在被读取OM/GET状态.我们不直接使用todo的标题,因为用户可能会在编辑过程中中止,然后会丢失原始值。编辑文本只是暂时的头衔。


    现在就这样,孩子们!在第4幕我们将看到用户如何与应用程序交互。


评论由迪斯科