由于 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ā)不太一樣。
在微信小程序端的自定義組件中,只有在 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)。
在 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)置組件的事件綁定寫法保持一致了。
自 v1.3.0-beta.0 沒有這條限制
前面已經(jīng)提到小程序端的組件傳入函數(shù)的原理,所以在小程序端不要在組件中打印傳入的函數(shù),因?yàn)槟貌坏浇Y(jié)果,但是 this.props.onXxx && this.props.onXxx() 這種判斷函數(shù)是否傳入來進(jìn)行調(diào)用的寫法是完全支持的。
由于小程序不支持將 data 中任何一項(xiàng)的 value 設(shè)為 undefined ,在 setState 的時(shí)候也請避免這么用。你可以使用 null 來替代。
在微信小程序端是通過 <slot /> 來實(shí)現(xiàn)往自定義組件中傳入元素的,而 Taro 利用 this.props.children 在編譯時(shí)實(shí)現(xiàn)了這一功能, this.props.children 會直接被編譯成 <slot /> 標(biāo)簽,所以它在小程序端屬于語法糖的存在,請不要在組件中打印它。
自 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 上用同名的字段,因?yàn)檫@些字段在微信小程序中都會掛在 data 上。
由于微信小程序里頁面在 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ù)的頁面則沒有任何影響。
很多細(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ò)的情況。
在 Taro 中,JS 代碼里必須書寫單引號,特別是 JSX 中,如果出現(xiàn)雙引號,可能會導(dǎo)致編譯錯(cuò)誤。
不要以解構(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 可能取值分別為 PAGE 和 COMPONENT,開發(fā)者可以根據(jù)此變量的取值分別采取不同邏輯。
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')
更多建議: