Thinking in React Implemented by Reagent
前言?本文是学习Thinking in React这一章后的记录,并且用Reagent实现其中的示例。 概要
一、构造恰当的数据结构
?VDom让我们可以将Model到View的映射交出,而更专注于数据和数据结构本身,即是折腾数据和数据结构才是我们的主要工作。因此我们要设计出与View中组件结构对应的数据结构,然后将不符合该数据结构的数据做一系列转换,然后将数据交给React就好了。 FilterableProductTable |_SearchBar |_ProductTable |_ProductCategoryRow |_ProductRow ?而数据则从顶层View组件往下流动,各层提取各自数据进行渲染。 二、从静态非交互版本开始
?从设计(他人或自己)那得到设计稿或HTML模板,我们就可以开始着手重构模板、添加交互效果和填充业务逻辑和服务端交互等功能了。且慢,我们先不着急动手,而是要先分清工作步骤,才能有条不紊地包质保量工作哦!
(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",:name "Baseball"} {:category "Sporting Goods",:price "$29.99",:stocked false,:name "Basketball"} {:category "Electronics",:price "$99.99",:name "iPod Touch"} {:category "Electronics",:price "$399.99",:name "iPhone 5"} {:category "Electronics",:price "$199.99",: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)]])
三、追加交互代码?交互实质上就是触发View状态变化,那么就必须提供一种容器来暂存当前View的状态,而这个在React就是state了。 (ns demo.core (:require [reagent.core :as re]) (def products [ {:category "Sporting Goods",: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/fsjohn... ^_^肥仔John 参考https://reactjs.org/docs/thin... (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |