最佳實(shí)踐

2020-05-12 17:46 更新

關(guān)于 JSX 支持程度補(bǔ)充說明

由于 JSX 中的寫法千變?nèi)f化,我們不能支持到所有的 JSX 寫法,同時(shí)由于微信小程序端的限制,也有部分 JSX 的優(yōu)秀用法暫時(shí)不能得到很好地支持,特在此補(bǔ)充說明一下對于 JSX 的支持程度:

以上的規(guī)則在 Taro 默認(rèn)生成的模板都有 ESLint 檢測,無需做任何配置。如果你的編輯器沒有安裝 ESLint 插件可以參考以下教程在你的編輯器安裝:

默認(rèn)情況下 Taro 的編譯器也會對無法運(yùn)行的代碼進(jìn)行警告,當(dāng)沒有調(diào)用棧信息時(shí)代碼是可以生成的。如果你需要在編譯時(shí)禁用掉 ESLint 檢查,可以在命令前加入 ESLINT=false 參數(shù),例如:

$ ESLINT=false taro build --type weapp --watch

最佳編碼方式

經(jīng)過較長時(shí)間的探索與驗(yàn)證,目前 Taro 在微信小程序端是采用依托于小程序原生自定義組件系統(tǒng)來設(shè)計(jì)實(shí)現(xiàn) Taro 組件化的,所以目前小程序端的組件化會受到小程序原生組件系統(tǒng)的限制,而同時(shí)為了實(shí)現(xiàn)以 React 方式編寫代碼的目標(biāo),Taro 本身做了一些編譯時(shí)以及運(yùn)行時(shí)的處理,這樣也帶來了一些值得注意的約束,所以有必要闡述一下 Taro 編碼上的最佳實(shí)踐。

組件樣式說明

微信小程序的自定義組件樣式默認(rèn)是不能受外部樣式影響的,例如在頁面中引用了一個(gè)自定義組件,在頁面樣式中直接寫自定義組件元素的樣式是無法生效的。這一點(diǎn),在 Taro 中也是一樣,而這也是與大家認(rèn)知的傳統(tǒng) Web 開發(fā)不太一樣。

給組件設(shè)置 defaultProps

在微信小程序端的自定義組件中,只有在 properties 中指定的屬性,才能從父組件傳入并接收

Component({
  properties: {
    myProperty: { // 屬性名
      type: String, // 類型(必填),目前接受的類型包括:String, Number, Boolean, Object, Array, null(表示任意類型)
      value: '', // 屬性初始值(可選),如果未指定則會根據(jù)類型選擇一個(gè)
      observer: function (newVal, oldVal, changedPath) {
         // 屬性被改變時(shí)執(zhí)行的函數(shù)(可選),也可以寫成在 methods 段中定義的方法名字符串, 如:'_propertyChange'
         // 通常 newVal 就是新設(shè)置的數(shù)據(jù), oldVal 是舊數(shù)據(jù)
      }
    },
    myProperty2: String // 簡化的定義方式
  }
  ...
})

而在 Taro 中,對于在組件代碼中使用到的來自 props 的屬性,會在編譯時(shí)被識別并加入到編譯后的 properties 中,暫時(shí)支持到了以下寫法

this.props.property

const { property } = this.props

const property = this.props.property

但是一千個(gè)人心中有一千個(gè)哈姆雷特,不同人的代碼寫法肯定也不盡相同,所以 Taro 的編譯肯定不能覆蓋到所有的寫法,而同時(shí)可能會有某一屬性沒有使用而是直接傳遞給子組件的情況,這種情況是編譯時(shí)無論如何也處理不到的,這時(shí)候就需要大家在編碼時(shí)給組件設(shè)置 defaultProps 來解決了。

組件設(shè)置的 defaultProps 會在運(yùn)行時(shí)用來彌補(bǔ)編譯時(shí)處理不到的情況,里面所有的屬性都會被設(shè)置到 properties 中初始化組件,正確設(shè)置 defaultProps 可以避免很多異常的情況的出現(xiàn)。

組件傳遞函數(shù)屬性名以 on 開頭

在 v1.3.0-beta.0 之后,自定義組件間的事件傳遞可以不用 on 開頭,但內(nèi)置組件的事件依然是以 on 開頭的,為了一致性我們?nèi)匀煌扑]你以 on 開頭命名你的事件。

在 Taro 中,父組件要往子組件傳遞函數(shù),屬性名必須以 on 開頭

// 調(diào)用 Custom 組件,傳入 handleEvent 函數(shù),屬性名為 onTrigger
class Parent extends Component {

  handleEvent () {

  }

  render () {
    return (
      <Custom onTrigger={this.handleEvent}></Custom>
    )
  }
}

這是因?yàn)椋⑿判〕绦蚨私M件化是不能直接傳遞函數(shù)類型給子組件的,在 Taro 中是借助組件的事件機(jī)制來實(shí)現(xiàn)這一特性,而小程序中傳入事件的時(shí)候?qū)傩悦麑懛?nbsp;bindmyevent 或者 bind:myevent

<!-- 當(dāng)自定義組件觸發(fā) myevent 事件時(shí),調(diào)用 onMyEvent 方法 -->
<component-tag-name bindmyevent="onMyEvent" />
<!-- 或者可以寫成 -->
<component-tag-name bind:myevent="onMyEvent" />

所以 Taro 中約定組件傳遞函數(shù)屬性名以 on 開頭,同時(shí)這也和內(nèi)置組件的事件綁定寫法保持一致了。

小程序端不要在組件中打印傳入的函數(shù)

自 v1.3.0-beta.0 沒有這條限制

前面已經(jīng)提到小程序端的組件傳入函數(shù)的原理,所以在小程序端不要在組件中打印傳入的函數(shù),因?yàn)槟貌坏浇Y(jié)果,但是 this.props.onXxx && this.props.onXxx() 這種判斷函數(shù)是否傳入來進(jìn)行調(diào)用的寫法是完全支持的。

小程序端不要將在模板中用到的數(shù)據(jù)設(shè)置為 undefined

由于小程序不支持將 data 中任何一項(xiàng)的 value 設(shè)為 undefined ,在 setState 的時(shí)候也請避免這么用。你可以使用 null 來替代。

小程序端不要在組件中打印 this.props.children

在微信小程序端是通過 <slot /> 來實(shí)現(xiàn)往自定義組件中傳入元素的,而 Taro 利用 this.props.children 在編譯時(shí)實(shí)現(xiàn)了這一功能, this.props.children 會直接被編譯成 <slot /> 標(biāo)簽,所以它在小程序端屬于語法糖的存在,請不要在組件中打印它。

支持 props 傳入 JSX

自 1.1.9 開始支持

支持 props 傳入 JSX,但是元素傳入 JSX 的屬性名必須以 render 開頭

例如,子組件寫法

class Dialog extends Component {
  render () {
    return (
      <View className='dialog'>
        <View className='header'>
          {this.props.renderHeader}
        </View>
        <View className='body'>
          {this.props.children}
        </View>
        <View className='footer'>
          {this.props.renderFooter}
        </View>
      </View>
    )
  }
}

父組件調(diào)用子組件時(shí)傳入 JSX

class App extends Component {
  render () {
    return (
      <View className='container'>
        <Dialog
          renderHeader={
            <View className='welcome-message'>Welcome!</View>
          }
          renderFooter={
            <Button className='close'>Close</Button>
          }
        >
          <View className="dialog-message">
            Thank you for using Taro.
          </View>
        </Dialog>
      </View>
    )
  }
}

組件屬性傳遞注意

不要以 id、class、style 作為自定義組件的屬性與內(nèi)部 state 的名稱,因?yàn)檫@些屬性名在微信小程序小程序中會丟失。

組件 state 與 props 里字段重名的問題

不要在 state 與 props 上用同名的字段,因?yàn)檫@些字段在微信小程序中都會掛在 data 上。

小程序中頁面生命周期 componentWillMount 不一致問題

由于微信小程序里頁面在 onLoad 時(shí)才能拿到頁面的路由參數(shù),而頁面 onLoad 前組件都已經(jīng) attached 了。因此頁面的 componentWillMount 可能會與預(yù)期不太一致。例如:

// 錯(cuò)誤寫法
render () {
  // 在 willMount 之前無法拿到路由參數(shù)
  const abc = this.$router.params.abc
  return <Custom adc={abc} />
}

// 正確寫法
componentWillMount () {
  const abc = this.$router.params.abc
  this.setState({
    abc
  })
}
render () {
  // 增加一個(gè)兼容判斷
  return this.state.abc && <Custom adc={abc} />
}

對于不需要等到頁面 willMount 之后取路由參數(shù)的頁面則沒有任何影響。

組件的 constructor 與 render 提前調(diào)用

很多細(xì)心的開發(fā)者應(yīng)該已經(jīng)注意到了,在 Taro 編譯到小程序端后,組件的 constructor 與 render 默認(rèn)會多調(diào)用一次,表現(xiàn)得與 React 不太一致。

這是因?yàn)椋琓aro 的組件編譯后就是小程序的自定義組件,而小程序的自定義組件的初始化時(shí)是可以指定 data 來讓組件擁有初始化數(shù)據(jù)的。開發(fā)者一般會在組件的 constructor 中設(shè)置一些初始化的 state,同時(shí)也可能會在 render 中處理 state 與 props 產(chǎn)生新的數(shù)據(jù),在 Taro 中多出的這一次提前調(diào)用,就是為了收集組件的初始化數(shù)據(jù),給自定義組件提前生成 data ,以保證組件初始化時(shí)能帶有數(shù)據(jù),讓組件初次渲染正常。

所以,在編碼時(shí),需要在處理數(shù)據(jù)的時(shí)候做一些容錯(cuò)處理,這樣可以避免在 constructor 與 render 提前調(diào)用時(shí)出現(xiàn)由于沒有數(shù)據(jù)導(dǎo)致出錯(cuò)的情況。

JS 編碼必須用單引號

在 Taro 中,JS 代碼里必須書寫單引號,特別是 JSX 中,如果出現(xiàn)雙引號,可能會導(dǎo)致編譯錯(cuò)誤。

環(huán)境變量 process.env 的使用

不要以解構(gòu)的方式來獲取通過 env 配置的 process.env 環(huán)境變量,請直接以完整書寫的方式 process.env.NODE_ENV 來進(jìn)行使用

// 錯(cuò)誤寫法,不支持
const { NODE_ENV = 'development' } = process.env
if (NODE_ENV === 'development') {
  ...
}

// 正確寫法
if (process.env.NODE_ENV === 'development') {

}

使用 this.$componentType 來判斷當(dāng)前 Taro.Component 是頁面還是組件

this.$componentType 可能取值分別為 PAGE 和 COMPONENT,開發(fā)者可以根據(jù)此變量的取值分別采取不同邏輯。

原生小程序組件傳遞 props 給 Taro 組件

Taro v1.3+ 對 props 系統(tǒng)進(jìn)行了改造,使得不能兼容原生組件通過 properties 傳入的屬性。

目前可以通過把所有需要傳入 Taro 組件的 props,通過借助 extraProps 屬性來解決。

// 小程序組件常規(guī) props 傳遞
<plugin title="{{name}}" desc="{{desc}}" bindonclick="onClick"></plugin>

// 原生小程序組件調(diào)用 Taro 組件時(shí)需要改造成以下形式:
this.setData({
  extraProps: {
    name,
    desc,
    onClick: this.onClick
  }
})
<plugin extraProps="{{extraProps}}" ></plugin>

全局變量

在 Taro 中推薦使用 Redux 來進(jìn)行全局變量的管理,但是對于一些小型的應(yīng)用, Redux 就可能顯得比較重了,這時(shí)候如果想使用全局變量,推薦如下使用。

新增一個(gè)自行命名的 JS 文件,例如 global_data.js,示例代碼如下

const globalData = {}

export function set (key, val) {
  globalData[key] = val
}

export function get (key) {
  return globalData[key]
}

隨后就可以在任意位置進(jìn)行使用啦

import { set as setGlobalData, get as getGlobalData } from './path/name/global_data'

setGlobalData('test', 1)

getGlobalData('test')


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號