今天分享一個react應用,應在第一篇作品中說要做一個react+redux+xxx的應用。已經做完一部分,拿出來分享。github地址為:點我就可以咯~
這里實現了一個新聞移動站的spa。本來想寫pc端的,但是比較懶,而且因為主要是react的項目,關於css和布局的細節就是糊弄人的了。T.T,這里只說關於這個項目的js部分。
這里的功能很簡單,有一下幾點:
1,按”心“排序


當比上一個多了,就會排到前面。
2.評論部分
新聞的評論部分類似qq空間的評論

當然,也可以點擊新聞回復的哦。
=============================================
大家看到了,功能比較簡單,大家clone 項目下來,直接能用的,里面已經傳了我用webpack打包好的文件。
=============================================
bundle.js有3m+,這個完全是因為我加了很多庫進去,比如輪播圖的swiper等等,而且這些東西都是沒有壓縮過的。你壓縮完之后,會覺得react做移動端也可以的。
就不要再問我為什么不用rn做這個。。因為我不會T.T
=============================================
要看懂本文也需要一定的基礎,比如es6基礎,react和redux基礎。
=============================================
最后一點廢話,這個東西還沒有做完,只是一部分,接下來會用redux的router把它作為一個完全的spa,並且完善它的測試部分。大家期待吧~
=============================================(主文分界線)
好,接下來介紹我們的主角redux,不會的可以轉到我的另一篇博文:點此
redux,昨天花了一上午,竟然看完了它全部的源碼。跟你們說,它未壓縮的redux.js僅有600行。angular已經1w+行了。。。
主要的是很簡單,源碼一看就懂,而且redux完全是fp,也就是函數式編程,它內置了一些函數式編程的例子。運用fp的庫還有lodas和underscore。我將會寫另一篇介紹fp與redux的博文~~
分析代碼之前,先給出文件目錄:

這個目錄是官方example的目錄,我就直接拿來用了。webpack整理的文件在public中,bootstrap沒有在webpack中打包,項目中一般也用不到,其他的css和js文件都打包進去了。
其中,fonts是字體,dist存放了webpack打包后的js和css文件,public里面是輪播圖js文件和圖片文件。test是測試文件,現在還沒寫。因為不是tdd。。
剩下的actions存放的是redux的action文件。components存放的是react的組件,containers是redux如何封裝組件的配置文件。reducers是redux的reducer文件,store是創建store的配置文件。
webpack主入口是index.js 它里面是添加了一些應用需要的文件,比如import Swiper from "./public/js/swiper-3.3.1.min.js"和import "./public/js/swiper.min.css",還有main.css
import React from 'react' import { render } from 'react-dom' import { Provider } from 'react-redux' import App from './containers/App' import configureStore from './store/configureStore' import "./dist/main.css"; import Swiper from "./public/js/swiper-3.3.1.min.js" import "./public/js/swiper.min.css" import 'react-bootstrap'; const store = configureStore(); render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') )
大家會看到這個項目跟上一個redux入門中的項目結構,甚至代碼都類似,因為就是從上一個代碼的基礎上改的,不明白可以看上一篇文章。
主頁就不多說了,開始的頁面布局和引入css文件和打包之后的js文件。
主要說一下上面提到的功能。
首先是排序。排序的原理是什么?根據心排序,心的多少。

Box是那三個新聞,這里會根據children來循環遍歷出來,那個children是啥呢?是redux的store的counter數據排序之后的數據。
可以看到,我自己寫了一個數據排序,根據數據的val屬性排序,然后遍歷,就是完成了心的特性。
state={ counter:{ one:{id:1,counter:0,title:"xxxx" ,time:1}, two:{id:2,counter:0,title:"xxxx", time:1}, three:{id:3,counter:0,title:"xxxx",time:1} } }
這里的counter數據,counter是心的數量。排序就不說了,看代碼吧。
評論功能呢,有三個難點。1是點擊回復彈出input框,2是如何回復當前的評論。比如我回復的評論必須是這個評論,而不是下一個。3就是如何把評論內容顯示出來。
最難的就是2了。這個還要設計一下store的數據結構。我用了一個小方法避免了添加id。這個以后再說。
1。點擊彈出input框。
寫react或者ng應用也不能用jquery的思想寫了。點擊彈出不能用click事件操作dom了。轉變為react的思想,props和state。於是,要這樣寫。

這是根據state渲染dom阿,然后點擊操作state。對了,react有個操作state的方法和初始化state的方法來着。叫getInitialState。

這里有個隱藏的坑,es6的寫法不能用getInitialState。於是我就像上面這樣寫。es6怎么寫state呢。於是我在下面的組件里又這樣寫:

這個state成為了這個組件的一個屬性,但是確實沒法用getInitialState了。不過可以用 this.setState({display: false})。這樣寫。來操作state
2,這個比較麻煩,首先看一下我設計的評論的store:
var data=[ [ { text:"這里是評論1", huifu:["huifuxxxxxxxxxxxxx",'2xxxxxxxxxxxxxxxxxxxx','3xxxxxxxxxxxxxxxxx'] }, { text:"這里是評論1.2", huifu:["huifuxxxxxxxxxxxxx"] } ],[ { text:"這里是評論2", huifu:["huifuxxxxxxxxxxxxx",'2xxxxxxxxxxxxxxxxxxxx','3xxxxxxxxxxxxxxxxx'] } ],[ { text:"這里是評論3", huifu:["huifuxxxxxxxxxxxxx",'2xxxxxxxxxxxxxxxxxxxx','3xxxxxxxxxxxxxxxxx'] } ] ]
這是整個評論的部分,包括回復。如果你要添加評論就在data[文章id].push(一樣結構的評論數據),回復也是直接添加數據。
問題來了,那我們怎么保證這個回復是這個評論的呢,比如我回復123,你怎么知道是評論1的還是評論1.2(代碼中的評論1.2)的呢?
這里有個小方法。我的評論框是獨立於遍歷之外的,就是說,你不能給他傳一個文章id。那怎么辦?
它取本組件的state。然后評論操作state。就是這樣。評論在打開一個回復input的時候,傳入本評論的id,改變本組件的state,然后就不管它的事了。
這里的小方法避免了每個評論都加一個id屬性,而是一個評論數組,用的就是數組map方法的keys--

keys,是數組的鍵,也就是0,1,2,3用這個當作文章id。可以的!
注意這里你循環出子組件的時候,必須給他一個key的props,由於react的diff算法,必須保證子組件的位置和渲染正確,傳一個key,那正好,沒有id我就用這里的keys傳了:

這樣就沒問題了。
3。顯示的問題,就是上面的遍歷的問題了,輸入框的顯示就是組件自身state的問題了。
看組件是如何顯示:
{ data[newId].map(function (items,keys) { return ( <div key={keys} className="body-text"> <h5>游客: <a onClick={that.handleClick.bind(that,keys)}>回復</a> <a href="">轉發</a></h5> <p>{items.text}</p> { items.huifu.map(function (item,keyss) { return ( <div key={keyss}> <h5 className="huifu-user">游客回復:<a onClick={that.handleClick.bind(that,keys)} >回復</a> <a href="">轉發</a></h5> <p className="huifu">{item}</p> </div> ) }) } </div> ) })
}
data數組是我們的數據,上面給了格式。循環遍歷。
主要的是回復框的顯示,操作state,這里給了他一個display屬性,但是他不是true和false,而是false和keys,這個keys就是當前評論的id,這個id成為遍歷的keys屬性。
1的時候那張圖就是根據display顯示,這就不多說了。
react的優勢:
其實這么多文件夾,這么多js文件,用js寫,邏輯又清楚又快,而用react寫還帶有學習成本。為啥用react寫。拋開趕前端潮流不說。react的優勢在於維護起來爽翻天。
js寫這些邏輯剛開始寫完是很清晰,我覺得過一段時間以后,想維護就很難了吧。還有一點,我想改數據的時候直接修改state,想加一個新聞就復用我的組件,根據react的虛擬dom的算法,也是不慢的。
用redux的優勢就是等這個新聞項目做大,一堆一堆的js代碼,如果有redux維護那就簡單多了。因為純函數的關系,redux的測試也是非常好寫的。redux壓縮前600行代碼,加上react也是輕量級框架,這點也是很受人好評的。
用這些框架都是類似,都是數據流,他們讓你用數據控制頁面。ng也是如此,操作僅僅是修改數據,而不會頻繁的操作dom。這是框架的優點。react在此基礎上做到的低耦合,單項數據流。經常聽到有react維護比較爽的呼聲。-。-好維護,低耦合,輕量級。正好符合現在前端對框架的要求。於是好多人選擇了react。還有JSX的寫法也是比較爽的0.0react背后還有facebook撐腰。嗯,必火。。。
關於本新聞端的問題:
問題在於這里:三篇新聞,每一篇當作一個事件來處理,於是--
export const LOVE_COUNTER_ONE = 'LOVE_COUNTER_ONE' export const LOVE_COUNTER_TWO = 'LOVE_COUNTER_TWO' export const LOVE_COUNTER_THREE = 'LOVE_COUNTER_THREE' export const TXST_COUNTER_ONE = 'TXST_COUNTER_ONE' export const TXST_COUNTER_TWO = 'TXST_COUNTER_TWO' export const TXST_COUNTER_THREE = 'TXST_COUNTER_THREE' export const HF_COUNTER_ONE = 'HF_COUNTER_ONE' export const HF_COUNTER_TWO = 'HF_COUNTER_TWO' export const HF_COUNTER_THREE = 'HF_COUNTER_THREE'
有人會說,如果100篇新聞,豈不是寫n多的action?
當初在寫的時候,想的是作為新聞的主頁,我只放3個新聞,后面加一個更多,點開打開新聞列表頁。當然,如果把這個作為新聞列表頁那確實要寫n多的xxx。。
那當這個新聞端改為新聞列表頁怎么寫呢?
首先構建一個store,把新聞id,新聞內容寫進去。當然也可以組合它的評論和回復,不組合,通過id關聯也是可以的。。(怎么感覺像數據庫了0.0)
那這里的action就變了,改為TXST_COUNTER_NEWS,當然,這個action需要傳文章的id。這個不麻煩。
reducer這里就根據文章id操作store,如果不組合評論和回復,那么,這個新聞store只需要刪減新聞內容。注意新聞刪了,對應的評論和回復也要刪除。
組合評論和回復呢,那么也是同樣,評論和回復的內容留給游客們去添加。
組件里就注意了,因為新聞組合了,那么上面就需要傳一個新聞id,智能組件根據id傳方法與數據給呆滯組件。。原理是這樣。大家可以試着修改一下,自己動手能學到很多東西。
還有就是webpack打包文件太大怎么辦。我這個文件3m,本地加載都要143ms,這段時間3張下載完的圖片並排,很丑。。
這里的減少體積大小的方法就是關閉source map,devTool也關了。重復的文件打包成common.js,還有就是壓縮文件- -,當然這些都是生成環境下了。
這里測試了一下(未傳到github),未壓縮前可以弄到864k,當然公共庫,比如Swiper可以用cdn,壓縮完后這樣一個數量級的應用就可以用在移動端了。
這里的操作是-刪除沒用的react-bootstrap,刪除重復的style-loader,刪除source-map及webpack hot replace及一些webpack常用插件。
還有一點,把文件作為chunk按需加載,這個貌似這個場景下還是不需要的。
需要注意的就這么多,接下來會添加路由功能,使他真正的成為spa的應用。當然,大神的標志之一---會不會寫測試也會一並補齊。敬請期待~
最新更新:2016-04-25 單元測試已經補齊哦~ 博文地址:點我~ github地址:點我~
