5th 小程序項目結(jié)構(gòu)和框架

項目地址: https://github.com/mirrorhanyu/WeGit

掃碼體驗

mini-program-qrcode

小程序項目按照官方推薦的代碼組織結(jié)構(gòu)

WeGit
├── .editorconfig
├── .eslintrc
├── global.d.ts
├── package.json
├── project.config.json
├── tsconfig.json
├── config
│   ├── dev.js
│   ├── index.js
│   └── prod.js
└── src
    ├── app.scss
    ├── app.tsx
    ├── common.scss
    ├── index.html
    ├── actions
    ├── components
    │   ├── activity
    │   ├── common
    │   ├── footer
    │   ├── search
    │   ├── trending
    ├── constants
    ├── pages
    ├── reducers
    ├── store
    ├── types
    ├── utils
    └── wemark

生命周期和事件回調(diào)函數(shù)

Taro 遵循 React 語法規(guī)范搓幌,同樣是采用組件化思想迷郑,并保持了一致的組件生命周期懂更。

同時最蕾,小程序每個頁面指定頁面的初始數(shù)據(jù)、生命周期回調(diào)憨降、事件處理函數(shù)等,詳細(xì)看參考官方文檔

React 基礎(chǔ)

在我們開始之前咐容,我們可以簡單的回顧一遍 React 基本概念。

元素 (Elements)

我們知道蚂维,在 React 應(yīng)用中

Elements are the smallest building blocks of React apps.

翻譯過來戳粒,element 就是 React 中最小的單元。 它描述了屏幕上應(yīng)該展現(xiàn)什么內(nèi)容虫啥。

const element = <h1>Hello, world</h1>;

element 是 immutable(不可變的)蔚约,定義好后就決定了長什么模樣。

如果把一個不斷變化的 Component (比如一個倒計時的組件)看作一個不斷放映的電影涂籽,element 就是其中的一幀苹祟,描述那一秒屏幕上該展示什么。

想要在屏幕上展現(xiàn)一個element ,用 ReactDOM.render(element, document.getElementById('root’)) 去更新就可以了树枫。

組件化 (Components)

組件化的思想是指把所看到的 UI直焙,拆分為獨立的,可以復(fù)用的小組件砂轻。

Component 可以理解成一個函數(shù)奔誓,輸入就是 props,輸出就是上面提到的 elements搔涝。比如:

function Welcome(props) {
   return <h1>Hello, {props.name}</h1>;
}

如果采用 ES6 的語法:

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

當(dāng)我們想要渲染一個 Component 的時候厨喂,

const element = <Welcome name=“Han"/>;
ReactDOM.render(
  element,
  document.getElementById('root')
);

{name: 'Han'} 就是輸入的 props,<h1>Hello, Han</h1> 就是輸出庄呈,render函數(shù)會渲染在對應(yīng)的節(jié)點上

React 只會更新需要更新的節(jié)點蜕煌。

Props

React 相當(dāng)之靈活,但是有一個非常嚴(yán)格的規(guī)則:

All React components must act like pure functions with respect to their props.

React 要求我們不能改變 props诬留,必須是一個純函數(shù) (pure)斜纪。輸入不改變的話,如何做到改變輸出故响,從而使 UI 動態(tài)改變呢傀广?

于是我們就有了,

State

State 與 props 類似彩届,但是 state 是私有的伪冰,并且完全受控于當(dāng)前組件。

State 允許 React 組件隨用戶操作樟蠕、網(wǎng)絡(luò)響應(yīng)或者其他變化而動態(tài)更改輸出內(nèi)容贮聂。

具體可以參考這個例子

需要注意的三點:

  1. setState() 去修改 state
  2. setState() 異步的,出于性能考慮寨辩,React 可能會把多個 setState() 調(diào)用合并成一個調(diào)用吓懈。
  3. setState() 合并是淺合并
    因為State是私有的,如果想要傳遞 State靡狞,只能是”自上而下”的通過props作為輸入?yún)?shù)向子組件傳遞耻警。這種通常會成為單向數(shù)據(jù)流。

那么甸怕,如果兩個組件都需要一個同樣的數(shù)據(jù)源呢甘穿,或者兄弟組件會通信呢?

通常梢杭,我們可以可以將它提升至這些組件的最近共同父組件中温兼。但是,還有別的方法嗎武契?

Flux

Flux 是 facebook 提出的一種網(wǎng)頁端設(shè)計架構(gòu)(Architecture)

Flux 核心理念是實現(xiàn)了一種單向的數(shù)據(jù)流募判。簡單來說荡含,就是當(dāng)用戶進(jìn)行操作的時候,會從組件 dispatch 一個 action届垫,這個 action 流向 store释液,store 基于 action 對狀態(tài)進(jìn)行改動,然后 store 又觸發(fā)組件基于新的狀態(tài)重新渲染敦腔。

這樣的實現(xiàn)均澳,可以幫助視圖和業(yè)務(wù)邏輯的分離恨溜。業(yè)務(wù)邏輯控制中心數(shù)據(jù)源符衔,視圖基于數(shù)據(jù)源渲染。

<img src="https://user-gold-cdn.xitu.io/2019/8/8/16c6fc480d9f696b?w=1300&h=708&f=png&s=141989" width="600" alt="flux-unidirectional-data-flow"/>

Redux

Redux 是基于 Flux 思想的一種實現(xiàn)糟袁。

Redux 的三個基本原則(Three Principles)

  1. 單一數(shù)據(jù)源
    整個應(yīng)用的 state 被儲存在一棵 object tree 中判族,并且這個 object tree 只存在于唯一一個 store 中。
  2. State 是只讀的
    唯一改變 state 的方法就是觸發(fā) action项戴,action 是一個用于描述已發(fā)生事件的普通對象形帮。
  3. 使用純函數(shù)來執(zhí)行修改
    為了描述 action 如何改變 state tree ,你需要編寫 reducers周叮。

Redux 的單項數(shù)據(jù)流是這樣的:

  1. 調(diào)用 store.dispatch(action)
  2. Redux store 把當(dāng)前的 state 樹和 action 傳給 reducer 函數(shù)做計算下一個 state辩撑。
  3. 根 reducer 應(yīng)該把多個子 reducer 輸出合并成一個單一的 state 樹。
  4. Redux store 保存了根 reducer 返回的完整 state 樹仿耽。

同時合冀,為了從 Redux state 樹中讀取部分?jǐn)?shù)據(jù),并通過 props 來把這些數(shù)據(jù)提供給要渲染的組件项贺, React Redux 庫提供了 connect()方法君躺。
connect 可接受如下參數(shù)

  1. mapStateToProps 這個函數(shù)來指定如何把當(dāng)前 Redux store state 映射到展示組件的 props 中
  2. mapDispatchToProps() 方法接收 dispatch() 方法并返回期望注入到展示組件的 props 中的回調(diào)方法

小程序首頁數(shù)據(jù)是如何展示的

首先 connect 方法,mapStateToProps()开缎,mapDispatchToProps()

@connect(({trending}) => ({
  trending
}), (dispatch) => ({
  fetchDevelopers(since, language) {
    dispatch(fetchDevelopers(since, language))
  },
  fetchRepositories(since, language) {
    dispatch(fetchRepositories(since, language))
  },
  fetchLanguages() {
    dispatch(fetchLanguages())
  }
}))

在 Component 的 componentDidMount 生命周期回調(diào)函數(shù)里獲取 Trending language(火熱的開發(fā)語言)

this.props.fetchLanguages()

dispatch 會分發(fā)對應(yīng)的 action 出去

export const fetchLanguages = () => {
  return async (dispatch) => {
    try {
      dispatch({ type: FETCH_TRENDING_LANGUAGES_PENDING})
      const response = await Taro.request({
        url: 'https://example.com/trending-languages',
        method: 'GET'
      })
      dispatch({ type: FETCH_TRENDING_LANGUAGES_FULFILLED, payload: [ ...response.data] })
    } catch (e) {
      dispatch({ type: FETCH_TRENDING_LANGUAGES_REJECTED, payload: e })
    }
  }
}

對應(yīng)的 reducer 會處理收到當(dāng)前狀態(tài)樹和 action棕叫,從而計算下一個 state

export default function activity(state = {} as ActivityState, action) {
  switch (action.type) {
    case FETCH_ACTIVITIES_PENDING:
      return {
        ...state, isActivitiesUpdated: false
      }
    case FETCH_ACTIVITIES_REJECTED:
      return {
        ...state, isActivitiesUpdated: true
      }
    case FETCH_ACTIVITIES_FULFILLED:
      return {
        ...state,
        isActivitiesUpdated: true,
        activities: action.payload,
        username: action.addition.username,
        maxPagination: action.addition.maxPage,
        currentPagination: action.addition.currentPagination
      }
   }
}

還記得 connect 里的 mapStateToProps 嗎?

當(dāng) state 變化奕删,Component 里的 props 也會改變俺泣,從而使得 Component 重新渲染。

taro build

在本地開發(fā)的時候

yarn dev:weapp //taro build --type weapp —watch 會編譯預(yù)覽及打包完残,并會監(jiān)聽文件修改
yarn build:weapp //taro build --type weapp 不會監(jiān)聽文件修改伏钠,但會對代碼進(jìn)行壓縮打包

實測過程中,build:weapp 把生成的小程序從1000+kb 壓縮到 ~700kb

但是 build 之后可能會有些許區(qū)別坏怪,需要自行 End to end 測試

比如贝润,build 出來的小程序 Taro response 中,header 中的 Max-Page 會解析成 max-page

持續(xù)優(yōu)化的

  • [ ] 項目中 component 拆分可以更細(xì)致
  • [ ] actions 重復(fù)代碼
  • [ ] sass 管理
  • [ ] connect 計算屬性
  • [ ] 測試

參考鏈接

  1. Flux In-Depth Overview
  2. Redux Motivation
  3. Why Use React Redux
  4. React Performance Optimizing
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末铝宵,一起剝皮案震驚了整個濱河市打掘,隨后出現(xiàn)的幾起案子华畏,更是在濱河造成了極大的恐慌,老刑警劉巖尊蚁,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亡笑,死亡現(xiàn)場離奇詭異,居然都是意外死亡横朋,警方通過查閱死者的電腦和手機(jī)仑乌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來琴锭,“玉大人晰甚,你說我怎么就攤上這事【鎏” “怎么了厕九?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長地回。 經(jīng)常有香客問我扁远,道長,這世上最難降的妖魔是什么刻像? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任畅买,我火速辦了婚禮,結(jié)果婚禮上细睡,老公的妹妹穿的比我還像新娘谷羞。我一直安慰自己,他們只是感情好纹冤,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布洒宝。 她就那樣靜靜地躺著,像睡著了一般萌京。 火紅的嫁衣襯著肌膚如雪雁歌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天知残,我揣著相機(jī)與錄音靠瞎,去河邊找鬼。 笑死求妹,一個胖子當(dāng)著我的面吹牛乏盐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播制恍,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼父能,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了净神?” 一聲冷哼從身側(cè)響起何吝,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤溉委,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后爱榕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瓣喊,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年黔酥,在試婚紗的時候發(fā)現(xiàn)自己被綠了藻三。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡跪者,死狀恐怖棵帽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情坑夯,我是刑警寧澤岖寞,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站柜蜈,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏指巡。R本人自食惡果不足惜淑履,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望藻雪。 院中可真熱鬧秘噪,春花似錦、人聲如沸勉耀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽便斥。三九已至至壤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間枢纠,已是汗流浹背像街。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留晋渺,地道東北人镰绎。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像木西,于是被迫代替她去往敵國和親畴栖。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容