Thinking in React Implemented by Reagent

简介:

前言

 本文是学习Thinking in React这一章后的记录,并且用Reagent实现其中的示例。

概要

  1. 构造恰当的数据结构
  2. 从静态非交互版本开始
  3. 追加交互代码

一、构造恰当的数据结构

Since you’re often displaying a JSON data model to a user, you’ll find that if your model was built correctly, your UI (and therefore your component structure) will map nicely.

 VDom让我们可以将Model到View的映射交出,而更专注于数据和数据结构本身,即是折腾数据和数据结构才是我们的主要工作。因此我们要设计出与View中组件结构对应的数据结构,然后将不符合该数据结构的数据做一系列转换,然后将数据交给React就好了。
居上所述那么可以知道,数据结构就依赖View的结构,那么如何设计View的结构呢?是采用Top-down还是Bottom-up的方式呢?对于小型应用我们直接采用Top-down即可,对于大型应用则采用Bottom-up更合适。(根据过往经验将大规模的问题域拆分成多个小规模的问题域,然后对小问题域采用Top-down方式,若无法直接采用Top-down方式则继续拆分,然后将多个小问题域的值域组合即可得到大问题域的值域)
无论是Top-down还是Bottom-up方式,都要将View构建为树结构(这很符合DOM结构嘛)。因此得到如下结构

FilterableProductTable
|_SearchBar
|_ProductTable
  |_ProductCategoryRow
  |_ProductRow

 而数据则从顶层View组件往下流动,各层提取各自数据进行渲染。

二、从静态非交互版本开始

It’s best to decouple these processes because building a static version requires a lot of typing and no thinking, and adding interactivity requires a lot of thinking and not a lot of typing.

 从设计(他人或自己)那得到设计稿或HTML模板,我们就可以开始着手重构模板、添加交互效果和填充业务逻辑和服务端交互等功能了。且慢,我们先不着急动手,而是要先分清工作步骤,才能有条不紊地包质保量工作哦!

  1. 目标:得到符合React规范的View结构
  2. 目标:得到最低标准的可交互的React应用
  3. 目标:补充业务逻辑,细化交互
  4. 目标:连接远程数据源,细化交互
(ns demo.core
  (:require [reagent.core :as re])

(def products [
  {:category "Sporting Goods", :price "$49.99", :stocked true, :name "Football"}
  {:category "Sporting Goods", :price "$9.99", :stocked true, :name "Baseball"}
  {:category "Sporting Goods", :price "$29.99", :stocked false, :name "Basketball"}
  {:category "Electronics", :price "$99.99", :stocked true, :name "iPod Touch"}
  {:category "Electronics", :price "$399.99", :stocked false, :name "iPhone 5"}
  {:category "Electronics", :price "$199.99", :stocked true, :name "Nexus 7"}
])


(declare <filterable-product-table>
         <search-bar>
         <product-table>
         <product-category-row>
         <product-row>)

(declare get-rows)

(defn <filterable-product-table>
  [products]
  [:div
    [<search-bar>]
    [<product-table> products]])

(defn <search-bar>
  []
  [:form
    [:input {:placeholder "Search..."}]
    [:input {:type "checkbox"}]
    "Only show products in stock."])

(defn <product-table>
  [products]
  [:table
    [:thead
      [:tr
        [:th "Name"]
        [:th "Price"]]]
    [:tbody
      (get-rows products)]])

(defn assemble-rows
  [products]
   (reduce
    (fn [{:keys [cate] :as rows-info} product]
      (let [curr-cate (:category product)
            curr-rows (if (not= curr-cate cate)
                        (list ^{:key curr-cate}[<product-category-row> curr-cate])
                        (list))
            rows (cons ^{:key (:name product)} [<product-row> product] curr-rows)]
        (-> rows-info
          (assoc :cate curr-cate) ;; 更新cate值
          (update
            :rows
            (fn [o rows]
              (concat rows o))
            rows)))) ;; 更新rows值
    {:cate nil :rows '()}
    products))

(defn get-rows
  [products]
  (-> (assemble-rows products)
    :rows
    reverse))

(defn <product-category-row>
  [cate]
  [:tr
    [:td {:colSpan 2} cate]])

(defn <product-row>
  [product]
  [:tr
    [:td (when (:stocked product) {:style {:color "red"}})
      (:name product)]
    [:td (:price product)]])

thinking_in_react_implemented_by_reagent
这一步我们并没有提供交互功能,因此只会用到prop传递数据,绝对不会用到state的。而交互的意思是,对View的操作会影响应用数据,从而刷新View。

三、追加交互代码

 交互实质上就是触发View状态变化,那么就必须提供一种容器来暂存当前View的状态,而这个在React就是state了。

(ns demo.core
  (:require [reagent.core :as re])

(def products [
  {:category "Sporting Goods", :price "$49.99", :stocked true, :name "Football"}
  {:category "Sporting Goods", :price "$9.99", :stocked true, :name "Baseball"}
  {:category "Sporting Goods", :price "$29.99", :stocked false, :name "Basketball"}
  {:category "Electronics", :price "$99.99", :stocked true, :name "iPod Touch"}
  {:category "Electronics", :price "$399.99", :stocked false, :name "iPhone 5"}
  {:category "Electronics", :price "$199.99", :stocked true, :name "Nexus 7"}
])


(declare <filterable-product-table>
         <search-bar>
         <product-table>
         <product-category-row>
         <product-row>)

(declare get-rows
         validate-product)


(defn <filterable-product-table>
  [products]
  (let [search-text (re/atom "")
        stocked? (re/atom false)
        on-search-text-change #(reset! search-text (.. % -target -value))
        on-stocked?-change #(reset! stocked? (.. % -target -checked))]
    (fn []
      [:div
        [<search-bar> on-search-text-change on-stocked?-change]
        [<product-table> (filter (partial validate-product @search-text @stocked?) products)]])))

(defn validate-product
  [search-text stocked? product]
  (and (if stocked? (:stocked product) true)
       (as-> search-text %
         (re-pattern (str "(?i)" %))
         (re-find % (:name product)))))

(defn <search-bar>
  [on-search-text-change on-stocked?-change]
  [:form
    [:input {:placeholder "Search..."
             :onChange on-search-text-change}]
    [:input {:type "checkbox"
             :onChange on-stocked?-change}]
    "Only show products in stock."])

(defn <product-table>
  [products]
  [:table
    [:thead
      [:tr
        [:th "Name"]
        [:th "Price"]]]
    [:tbody
      (get-rows products)]])

(defn assemble-rows
  [products]
   (reduce
    (fn [{:keys [cate] :as rows-info} product]
      (let [curr-cate (:category product)
            curr-rows (if (not= curr-cate cate)
                        (list ^{:key curr-cate}[<product-category-row> curr-cate])
                        (list))
            rows (cons ^{:key (:name product)} [<product-row> product] curr-rows)]
        (-> rows-info
          (assoc :cate curr-cate) ;; 更新cate值
          (update
            :rows
            (fn [o rows]
              (concat rows o))
            rows)))) ;; 更新rows值
    {:cate nil :rows '()}
    products))

(defn get-rows
  [products]
  (-> (assemble-rows products)
    :rows
    reverse))

(defn <product-category-row>
  [cate]
  [:tr
    [:td {:colSpan 2} cate]])

(defn <product-row>
  [product]
  [:tr
    [:td (when (:stocked product) {:style {:color "red"}})
      (:name product)]
    [:td (:price product)]])

注意:reagent中使用state时,需要定义一个返回函数的高阶函数来实现。

(defn <statefull-cmp> [data]
  (let [local-state (re/atom nil)
        on-change #(reset! local-state (.. % -target -value))]
    (fn []
      [:div
        [:input {:onChange on-change}]
        [:span @local-state]])))

(re/render [<statefull-cmp> 1]
           (.querySelector js/document "#app"))

总结

 尊重原创,转载请注明转自:http://www.cnblogs.com/fsjohnhuang/p/7692956.html ^_^肥仔John

参考

https://reactjs.org/docs/thinking-in-react.html

如果您觉得本文的内容有趣就扫一下吧!捐赠互勉!

 
本文转自 ^_^肥仔John博客园博客,原文链接: http://www.cnblogs.com/fsjohnhuang/p/7692956.html /,如需转载请自行联系原作者
相关文章
|
10月前
|
前端开发 API
react报错ReactDOM.render is no longer supported in React 18. 解决
react报错ReactDOM.render is no longer supported in React 18. 解决
124 0
|
10月前
|
前端开发 数据安全/隐私保护
React高阶组件(Higher-Order Components)及其应用
React高阶组件(Higher-Order Components)及其应用
56 0
|
前端开发
react项目实战学习笔记-学习9-ReactDOM.render is no longer supported in React 18
react项目实战学习笔记-学习9-ReactDOM.render is no longer supported in React 18
112 0
|
JavaScript 前端开发 测试技术
使用 React Testing Library 的 15 个常见错误(上)
哈喽,大家好,我是海怪。 刚开始我在写项目的单测方案的时候,老板就让我能够写一些单测的规范。虽然表面上我非常自然地说:没问题,但是心里还是慌得不行:以前我自己写单测也没啥规范呀,直接开干就好了。 最近一直在看 Kent 的文章,刚好看到他写的这篇 《Common mistakes with React Testing Library》,里面列举了很多别人写单测时经常犯的一些错误 。正好可以作为单测规范的参考。所以,今天就把这篇文章也分享给大家~
使用 React Testing Library 的 15 个常见错误(上)
|
JavaScript 前端开发 测试技术
使用 React Testing Library 的 15 个常见错误(下)
哈喽,大家好,我是海怪。 刚开始我在写项目的单测方案的时候,老板就让我能够写一些单测的规范。虽然表面上我非常自然地说:没问题,但是心里还是慌得不行:以前我自己写单测也没啥规范呀,直接开干就好了。 最近一直在看 Kent 的文章,刚好看到他写的这篇 《Common mistakes with React Testing Library》,里面列举了很多别人写单测时经常犯的一些错误 。正好可以作为单测规范的参考。所以,今天就把这篇文章也分享给大家~
使用 React Testing Library 的 15 个常见错误(下)
|
前端开发 JavaScript API
【墙裂推荐】Talking about hooks(上)
从React16.8开始,Hooks API正式被React支持,而就在最近,Vue作者尤雨溪翻译并发布了一篇自己的文章《Vue Function-based API RFC》,并在全文开头强调这是Vue 3.0最重要的RFC,并在文中提到 Function-based API 受 React Hooks 的启发,提供了一个全新的逻辑复用方案。
|
设计模式 前端开发 JavaScript
【墙裂推荐】Talking about hooks(下)
从React16.8开始,Hooks API正式被React支持,而就在最近,Vue作者尤雨溪翻译并发布了一篇自己的文章《Vue Function-based API RFC》,并在全文开头强调这是Vue 3.0最重要的RFC,并在文中提到 Function-based API 受 React Hooks 的启发,提供了一个全新的逻辑复用方案。
《The Great Gatsby》Day 19
Daisy沉醉于Gatsby家的繁华和精致,又因这5年逝去的时光而黯然神伤;Gatsby望着Daisy,欣喜又惶恐,前不久他还只能凝望海湾对面的Daisy家的那道绿光,期盼能与她充分,现在Daisy却离自己那么近,一切幸福显得有点不真实。
125 0
《The Great Gatsby》Day 12
舞会快结束的时候,Jordan和Gatsby也从书房出来了,Jordan告诉Nick她刚刚听到了最不可思议的事,但是又故意卖关子不肯说说是什么;她被伙伴们簇拥着上了车,和Nick告别时叮嘱Nick一定要给她打电话,Nick和Gatsby道别后也回家了。生活一天天过去,Nick也渐渐爱上了纽约。
71 0
《The Great Gatsby》Day 17
Nick答应邀请Daisy来家中做客,Gatsby非常感激,想给Nick介绍个赚钱的活,但被Nick拒绝了。约定见面的那天下起了倾盆大雨,Gatsby来到Nick家时焦虑不安,看起来彻夜未眠的样子,谈话也心不在焉;中途他打算离开时Daisy的车喇叭声正好在门外响起。Nick出门接Daisy,进门后却发现Gatsby不见了,正疑惑之时Gatsby敲门了,浑身湿透地站在门口。 3.好词佳句
91 0