關於cnode react的一比一實現

演示

演示圖片

寫在前面

本項目是學習react一個很是好的案例,不管是入門仍是想進階的人都能獲得幫助。若是你以爲本項目確實給你帶來了收穫,記得分享給他人和 star 一下。javascript

經過本項目,你能夠學到:css

  • 一個合理的react項目應該是什麼樣子
  • react/redux項目的目錄結構組織方式
  • 模塊化開發以及管理數據的方式
  • 如何抽象容器型和展現型組件
  • 佈局(Layout)組件的做用
  • 使用react-router-dom的最佳實踐
  • 如何使用immutable.js,並和react,redux結合
  • 經過約定命名減小錯誤
  • 本項目的各個組件的開發、抽象思路(我寫了大量的註釋來闡釋本身的想法,對某一功能的取捨,某一bug的思考)

啓動程序

  • 推薦使用yarn做爲包管理器

注意:本項目代碼遵循Airbnb編碼規範並開啓了eslint的嚴格模式,若是eslint出現error,則會編譯失敗html

# install dependencies
yarn install or npm install

# serve with hot reload
yarn start or npm start

# build for production with minification
yarn build or npm run build
複製代碼

Todo

  • [√] 話題列表頁
  • [√] 話題列表側邊欄
  • [√] 話題列表無限加載
  • [√] 話題詳情頁
  • [√] 話題詳情側邊欄
  • [√] 登陸狀態保存管理

由於cnode關於發帖的API已經被禁止,沒有實現發帖功能java

技術棧

數據管理

本項目採用 redux 並結合了 immutabe.js 做爲管理數據的方式。 並作了以下限制:node

  • redux中除了基本值類型,任何對象都要通過immutable提供fromJS方法轉換成immutable對象才能存入
  • 在上一條的約束下,redux store中的變量使用正常的命名方式
  • 組件中的任何變量的值若是是immutable對象,必須以$開頭

樣式模塊化

  • 全局樣式文件在統一在入口文件 index.js 處引入
  • 使用 styled-components 做爲組件樣式私有化方案

目錄組織

cnode-react
        ├─config(打包配置文件
        ├─docs(build生成的文件
        │  └─static
        │      ├─css
        │      ├─js
        │      └─media
        ├─public
        ├─scripts
        └─src
            ├─assets(公共資源
            │  ├─font
            │  ├─images
            │  └─styles
            ├─components(展現型且組件
            │  ├─Header
            │  ├─Image
            │  ├─Loading
            │  ├─Panel
            │  └─UserInfoPanel
            ├─containers(容器型組件
            │  ├─Detail
            │  │  ├─components(私有展現型組件
            │  │  │  ├─AuthorInfoPanel
            │  │  │  ├─ReplyList
            │  │  │  └─Topic
            │  │  └─store(模塊化store和常量定義處
            │  ├─Home
            │  │  ├─components
            │  │  │  ├─TopicList
            │  │  │  └─TopicListItem
            │  │  └─store
            │  └─Login
            │      ├─components
            │      └─store
            ├─Layout(佈局組件
            │  └─CommonLayout
            ├─store(全局store處,用來導入各處私有store
            └─utils(公用方法,如請求用request對象
複製代碼

其餘

使用eslint強制代碼規範

  • 代碼遵循Airbnb編碼規範

License

MITreact

遇到的問題以及反思

eslint沒法解析class靜態屬性,表現爲在針對下列代碼顯示unexpected token "="

class Foo extends Component {
  static propTypes = {
// ↑ unexpected topken "="
    foo: PropTypes.string,
  }
}

複製代碼

解決方法

這個是由於eslint默認的解析器並不支持es7的語法,安裝 eslint-babel,並在.babelrc裏把 parser 設置成babel-eslint便可ios

// .babelrc
module.exports = {
  // ...
  "parser": "babel-eslint",
  // ...
};

複製代碼

路由跳轉時高度不會重置的問題

解決方法

  • react-router-dom會對路由組件注入match屬性
  • componentDidUpdate裏拿到新舊的props
  • 經過拿到新舊不一樣的路徑,進行比對,若是不一樣執行scrollTo(0, 0);

這顯然不是好的解決方法,每次路由跳轉都回到頂部和路由不會重置都是糟糕的用戶體驗,我想了想,是否是能夠本身維持一個路由跳轉信息棧,用於保存路由信息和頁面高度,當跳轉時彈出棧中的一條路由信息和當前的路由進行比對,若是相符,就經過window.scrollTo滑動的保存的頁面高度,我以爲,這個方法的難點在於若是在合適的時機清空棧中的信息git

快速屢次切換路由,致使大量的網絡請求,數據被重複渲染或覆蓋

場景

論壇的帖子是經過sub(主題)分類的,頁面上的每個tab(標籤)對應一個sub,每一次點擊tab都會跳轉到相應路由,組件經過路由拿到當前sub,而後請求相應的數據。然而,當用戶快速在路由間切換時,若是沒作限制,就會致使大量的異步網絡請求,而且因爲異步特性,可能致使後發的請求比前發的先到,而後數據被前發的覆蓋掉。爲了解決這個問題,我嘗試了三種方法,每一種都比上一種要好一點。github

解決方法

  1. 是當每一次新的請求時,就隱藏掉頁面上的tab組件,只有請求完畢後才顯示,這個方法缺點很明顯,會形成很是很差 且能夠明確感知的用戶體驗
  2. 隨後,我決定在reducer裏作判斷,在action中把請求數據請求的那個tab信息帶上,若是和當前的tab不符合就丟掉數據,這個解決方法比上一個好,tab區域不會被隱藏,但仍是有問題,即用戶大量點擊的狀況下,依然會致使大量 的網絡請求,而且獲得數據後仍是會觸發action,雖然不合法的數據被丟掉了,可是大量的數據會致使網頁內存激增,性能降低。
  3. 最後,我想出了最佳的解決辦法就是,在每一次點擊tab致使的請求後,把之前的全部請求所有取消掉,由於請求是前一個tab的數據因此取消掉,不會形成任何影響(這個得益於axios提供了取消promise請求的功能)

通用組件防止內存泄漏問題

在我寫react時,總會出現一個下面的錯誤提示npm

Can't perform a React state update on an unmounted component. This is a no-op...... 複製代碼

###緣由

我封裝了Image組件,接受一個src和alt參數,與img標籤不同的地方在於,Image組件會在圖片未加載時顯示一個loading效果,我經過state管理組件是否處於loading的狀態,經過設置img元素的onload屬性,在觸發onload事件後,會觸發一個回調函數,設置state的loadding狀態爲false。然而,Image做爲一個通用組件,我沒有考慮到Image組件可能會請求未完成的狀況下,就被銷燬,而此時事件還在,當img元素加載完畢後,就去觸發回調,調用setState,而此時組件已經被銷燬,就致使了內存泄漏的問題。

分析出緣由後,解決這個問題就變得簡單了,在unmount的時候,設置 img.onload = null; 就好了。

反思

彷佛,react常見的內存泄漏緣由就是忘記組件unmount時銷燬事件,這牽扯到react事件的實現原理,react把全部事件掛載到window上進行代理,因此當元素被銷燬時,瀏覽器沒法銷燬與其相關的事件,由於事件沒有綁定在元素身上。

寫在最後

建議編碼的時候使用airbnb的編碼規範,airbnb做爲一個大型企業必定在js上吃了很多的虧,因此使用它們的編碼規範,不只使代碼看着舒服還能夠少踩不少的坑。

相關文章
相關標籤/搜索