从 React 到 ClojureScript

Presenter Notes

关于我

  • 题叶, tiye.me
  • jiyinyiyong
  • ChenYong
  • 饿了么, 前端
  • FP, GUI & Writing

Presenter Notes

目标

  • 介绍 ClojureScript
  • React 某些缺陷并不是必然
  • ClojureScript 一些例子

Presenter Notes

什么是 ClojureScript

Presenter Notes

ClojureScript

(def a 1)
(def add-1 [x] (+ x 1))
(println (add-1 a))

Presenter Notes

ClojureScript

  • Lisp 方言
  • 不可变数据
  • Rich Hickey

Presenter Notes

运行环境

  • Clojure -> JVM
  • ClojureScript -> Browsers
  • ClojureScript -> Node.js , JavaScriptCore

Presenter Notes

Learn Clojure in Y minutes

http://learnxinyminutes.com/docs/clojure

A Demo.

brew install lumo

Presenter Notes

React 有哪些特点

Presenter Notes

Pure Functional

  • 渲染 Virtual DOM 的纯函数
  • Store Updater 使用纯函数
  • 代码大量复用, 无副作用

Presenter Notes

Immutable Data Structure

  • 性能优化手段, 通过引用查找未改变的数据
  • 数据流的单向性, 可靠性

Presenter Notes

组件化

  • 组件成为代码复用的单元
  • 组件也是性能优化过程中的单元

Presenter Notes

React 有哪些问题

Presenter Notes

使用当中的问题

  • JSX, statement vs. expression
  • this 需要额外处理
  • immutable-js 和原生数据类型混用
  • this.state 不够灵活, this.setState 过程式编程

Presenter Notes

其他问题

  • Babel 更新频繁, 200+ 个版本, 配置繁杂
  • Redux 生态, unknown
  • 热替换手法复杂
  • 强行把组件封装成元素的结构, props, children

Presenter Notes

Better with ClojureScript

Presenter Notes

问题: JSX

一切皆是表达式

(if (> x 10) "big" "small")

非常时候构造 DSL.

Clojure 语言非常稳定, 不接受社区的 PR. 只能通过类库进行扩展.

Presenter Notes

问题: this

几乎没有 this. 完全通过函数来构造, 而不是 class.

Presenter Notes

问题: "数据混杂"

基于不可变数居, 严格限制可变数据的使用

(def a {:a 1, :b 2})
(assoc a :c 3)

(def b [1 2])
(conj b 3)

(def c '(6 5 4))
(cons 7 c)

(def d #{:a :b :c})
(conj d :d)

Presenter Notes

问题: this.state

atom 重新抽象 state:

(def click-count (r/atom 0))

(defn counting-component []
  [:div
   "The atom " [:code "click-count"] " has value: "
   @click-count ". "
   [:input {:type "button" :value "Click me!"
            :on-click #(swap! click-count inc)}]])

Presenter Notes

问题: Redux (替代方案)

Atom, 内置数据类型, Observable, 一个引用:

(def state-x (atom 0))
(add-watch state-x :logger (fn []
                               (println "Changed!")))
(reset! state-x 1) ; prints "Changed!"

(println @state-x) ; dereference to get value

Presenter Notes

Reagent

http://reagent-project.github.io/

Presenter Notes

Reagent: 挂载组件

(defn simple-component []
  [:div
   [:p "I am a component!"]
   [:p.someclass
    "I have " [:strong "bold"]
    [:span {:style {:color "red"}} " and red "] "text."]])

(defn render-simple []
  (r/render-component [simple-component]
                      (.-body js/document)))

Presenter Notes

Reagent: 处理 component state

(defn atom-input [value]
  [:input {:type "text"
           :value @value
           :on-change #(reset! value (-> % .-target .-value))}])

(defn shared-state []
  (let [val (r/atom "foo")] ; <---- atom
    (fn []
      [:div
       [:p "The value is now: " @val]
       [:p "Change it here: " [atom-input val]]])))

Presenter Notes

Reagent: 组件嵌套

(defn hello-component [name]
  [:p "Hello, " name "!"])

(defn say-hello []
  [hello-component "world"])

Presenter Notes

Respo: a font-end MVC library(experimental)

Presenter Notes

试验

  • 首屏加载时使用 Patching, 优化动画(渐进渲染)
  • 将 Virtual DOM 作为数据, 插入/改写
  • Virtual DOM for Canvas, 用框架来描述动画状态
  • Virtual tree for data, 服务端做数据的 diff, 带缓存优化(递进渲染)
  • core.async 来增强时间相关逻辑

Presenter Notes

Respo demo

Some demos...

Presenter Notes

Thx

Presenter Notes