最近一直在学习taro,网上搜的重点知识总结不多,因此想着本身写一篇我以为比较重要的知识点总结一下。css
如下文件组织规范为最佳实践的建议html
全部项目源代码请放在项目根目录 src
目录下,项目所需最基本的文件包括 入口文件 以及 页面文件react
app.js
src/pages
目录下一个可靠的 Taro 项目能够按照以下方式进行组织json
├── config 配置目录
| ├── dev.js 开发时配置
| ├── index.js 默认配置
| └── prod.js 打包时配置
├── src 源码目录
| ├── components 公共组件目录
| ├── pages 页面文件目录
| | ├── index index 页面目录
| | | ├── banner 页面 index 私有组件
| | | ├── index.js index 页面逻辑
| | | └── index.css index 页面样式
| ├── utils 公共方法库
| ├── app.css 项目总通用样式
| └── app.js 项目入口文件
└── package.json复制代码
Taro 中普通 JS/TS 文件以小写字母命名,多个单词如下划线链接,例如 util.js
、util_helper.js
小程序
Taro 组件文件命名遵循 Pascal 命名法,例如 ReservationCard.jsx
微信小程序
taro的书写规范大概和Eslint的规范相似,具体可参考官网连接:taro-docs.jd.com/taro/docs/s…数组
在 Taro 组件中会包含类静态属性、类属性、生命周期等的类成员,其书写顺序最好遵循如下约定(顺序从上至下)bash
onClickSubmit()
或者 onChangeDescription()
import Taro, { Component } from '@tarojs/taro'
import { View, Input } from '@tarojs/components'
class MyComponent extends Component {
state = {
myTime: 12
}
render () {
const { isEnable } = this.props // ✓ 正确
const { myTime } = this.state // ✓ 正确
return (
<View className='test'>
{isEnable && <Text className='test_text'>{myTime}</Text>}
</View>
)
}
}复制代码
因为 this.setState 异步的缘故,这样的作法会致使一些错误,能够经过给 this.setState 传入函数来避免微信
this.setState({
value: this.state.value + 1
}) // ✗ 错误
this.setState(prevState => ({ value: prevState.value + 1 })) // ✓ 正确复制代码
list.map(item => {
return (
<View className='list_item' key={item.id}>{item.name}</View>
)
})复制代码
由于在
componentDidMount
中调用this.setState
会致使触发更新app
import Taro, { Component } from '@tarojs/taro'
import { View, Input } from '@tarojs/components'
class MyComponent extends Component {
state = {
myTime: 12
}
componentDidMount () {
this.setState({ // ✗ 尽可能避免,能够在 componentWillMount 中处理
name: 1
})
}
render () {
const { isEnable } = this.props
const { myTime } = this.state
return (
<View className='test'>
{isEnable && <Text className='test_text'>{myTime}</Text>}
</View>
)
}
}
复制代码
import Taro, { Component } from '@tarojs/taro'
import { View, Input } from '@tarojs/components'
class MyComponent extends Component {
state = {
myTime: 12
}
componentWillUpdate () {
this.setState({ // ✗ 错误
name: 1
})
}
componentDidUpdate () {
this.setState({ // ✗ 错误
name: 1
})
}
render () {
const { isEnable } = this.props
const { myTime } = this.state
this.setState({ // ✗ 错误
name: 11
})
return (
<View className='test'>
{isEnable && <Text className='test_text'>{myTime}</Text>}
</View>
)
}
}复制代码
在 Taro 中全部默认事件如
onClick
、onTouchStart
等等,均以on
开头
import Taro, { Component } from '@tarojs/taro'
import { View, Input } from '@tarojs/components'
class MyComponent extends Component {
state = {
myTime: 12
}
clickHandler (e) {
console.log(e)
}
render () {
const { myTime } = this.state
return (
<View className='test' onClick={this.clickHandler}> // ✓ 正确
<Text className='test_text'>{myTime}</Text>
</View>
)
}
}复制代码
Taro 在小程序端实际上把 JSX 转换成了字符串模板,而一个原生 JSX 表达式其实是一个 React/Nerv 元素(react-element)的构造器,所以在原生 JSX 中你能够随意地对一组 React 元素进行操做。但在 Taro 中你只能使用
map
方法,Taro 转换成小程序中wx:for
在 Taro 中尺寸单位建议使用 px
、 百分比 %
,Taro 默认会对全部单位进行转换。在 Taro 中书写尺寸按照 1:1 的关系来进行书写,即从设计稿上量的长度 100px
,那么尺寸书写就是 100px
,当转成微信小程序的时候,尺寸将默认转换为 100rpx
,当转成 H5 时将默认转换为以 rem
为单位的值。
若是你但愿部分 px
单位不被转换成 rpx
或者 rem
,最简单的作法就是在 px 单位中增长一个大写字母,例如 Px
或者 PX
这样,则会被转换插件忽略。
结合过往的开发经验,Taro 默认以 750px
做为换算尺寸标准,若是设计稿不是以 750px
为标准,则须要在项目配置 config/index.js
中进行设置,例如设计稿尺寸是 640px
,则须要修改项目配置 config/index.js
中的 designWidth
配置为 640
组件能够将 UI 切分红一些的独立的、可复用的部件,这样你就只需专一于构建每个单独的部件。
组件从概念上看就像是函数,它能够接收任意的输入值(称之为 props
),并返回一个须要在页面上展现的 Taro 元素。
一个声明的组件决不能修改它本身的 props
。
随着应用日渐庞大,你能够经过类型检查捕获大量错误。要检查组件的属性,你须要配置特殊的 propTypes
属性:
import PropTypes from 'prop-types';
class Greeting extends Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};复制代码
关于 setState() 这里有三件事情须要知道:
例如,此代码不会从新渲染组件:
// Wrong
this.state.comment = 'Hello'
复制代码
应当使用 setState()
:
// Correct
this.setState({ comment: 'Hello' })复制代码
Taro 能够将多个 setState()
调用合并成一个调用来提升性能。
由于 this.state
和 props
必定是异步更新的,因此你不能在 setState
立刻拿到 state
的值,例如:
// 假设咱们以前设置了 this.state.counter = 0
updateCounter () {
this.setState({
counter: 1
})
console.log(this.state.counter) // 这里 counter 仍是 0
}
复制代码
正确的作法是这样,在 setState
的第二个参数传入一个 callback:
// 假设咱们以前设置了 this.state.counter = 0
updateCounter () {
this.setState({
counter: 1
}, () => {
// 在这个函数内你能够拿到 setState 以后的值
})
}复制代码
当你调用 setState()
,Taro 将合并你提供的对象到当前的状态中。
例如,你的状态可能包含几个独立的变量:
constructor(props) {
super(props)
this.state = {
posts: [],
comments: []
}
}
复制代码
而后经过调用独立的 setState()
调用分别更新它们:
componentDidMount() {
fetchPosts().then(response => {
this.setState({
posts: response.posts
});
});
fetchComments().then(response => {
this.setState({
comments: response.comments
})
})
}
复制代码
合并是浅合并,因此 this.setState({comments})
不会改变 this.state.posts
的值,但会彻底替换 this.state.comments
的值。
有时渲染的条件很是多,不论是 if-else
仍是 switch-case
来作条件渲染都会显得太麻烦。这时咱们可使用「表驱动法」:枚举渲染。
function Loading (props) {
const { loadingText, LOADING_STATUS, loadingStatus, onRetry } = props
return (
<View className='loading-status'>
{
{
'loading': loadingText,
'fail': <View onClick={onRetry}> 加载失败, 点击重试 </View>,
'no-more': '没有更多了'
}[loadingStatus] /** loadingStatus 是 `loading`、`fail`、`no-more` 其中一种状态 **/
}
</View>
)
}复制代码
下面,咱们使用 JavaScript 中的 map()
方法遍历 numbers
数组。对数组中的每一个元素返回 <Text>
标签,最后咱们获得一个数组 listItems
:
const numbers = [...Array(100).keys()] // [0, 1, 2, ..., 98, 99]
const listItems = numbers.map((number) => {
return <Text className='li'> 我是第 {number + 1} 个数字</Text>
})
复制代码
这段代码生成了一个 1 到 100 的数字列表。
可是在上面的代码,你会获得一个报错:提醒你当循环一个数组时应该提供 keys。Keys 能够在 DOM 中的某些元素被增长或删除的时候帮助 Nerv/小程序 识别哪些元素发生了变化。所以你应当给数组中的每个元素赋予一个肯定的标识。
taroKey
适用于循环渲染原生小程序组件,赋予每一个元素惟一肯定标识,转换为小程序的 wx:key
。
数组元素中使用的 key 在其兄弟之间应该是独一无二的。然而,它们不须要是全局惟一的。当咱们生成两个不一样的数组时,咱们可使用相同的 key
自
v1.3.0-beta.0
起支持
因为一个文件不能定义两个组件,但有时候咱们须要组件内部的抽象组件,这时类函数式组件就是你想要答案。假设咱们有一个 Class 组件,它包括了一个 Header
一个 Footer
,咱们能够这样定义:
class SomePage extends Taro.Component {
renderHeader () {
const { header } = this.state
return <View>{header}</View>
}
renderFooter (footer) {
return <View>{footer}</View>
}
render () {
return (
<View>
{this.renderHeader()}
{...}
{this.renderFooter('footer')}
</View>
)
}
}
复制代码
在 renderHeader
或 renderFooter
函数中,咱们能够访问类的 this
,也能够传入不限量的参数,这类型的函数也能够调用无限次数。但这样的写法也存在一些限制:
render
开头,render
后的第一个字母须要大写Sidebar
和 Dialog
这样的容器组件。咱们建议在这样的状况使用 this.props.children
来传递子元素:
class Dialog extends Component {
render () {
return (
<View className='dialog'>
<View className='header'>Welcome!</View>
<View className='body'>
{this.props.children}
</View>
<View className='footer'>-- divider --</View>
</View>
)
}
}
复制代码
这样就能容许其它组件在 JSX 中嵌套任意子组件传递给 Dialog
:
class App extends Component {
render () {
return (
<View className='container'>
<Dialog>
<View className="dialog-message">
Thank you for using Taro.
</View>
</Dialog>
</View>
)
}
}
复制代码
在 <Dialog />
JSX 标签内的任何内容都会做为它的子元素(Children)都会传递到它的组件。
请不要对 this.props.children
进行任何操做。Taro 在小程序中实现这个功能使用的是小程序的 slot
功能,也就是说你能够把 this.props.children
理解为 slot
的语法糖,this.props.children
在 Taro 中并非 React 的 ReactElement
对象,所以形如 this.props.children && this.props.children
、this.props.children[0]
在 Taro 中都是非法的。
this.props.children
没法用 defaultProps
设置默认内容。因为小程序的限制,Taro 也没法知道组件的消费者是否传入内容,因此没法应用默认内容。
不能把 this.props.children
分解为变量再使用。因为普通的 props
有一个确切的值,因此当你把它们分解为变量运行时能够处理,this.props.children
则不能这样操做,你必须显性地把 this.props.children
所有都写完整才能实现它的功能。
自
1.1.9
开始支持
有些状况你不只仅须要只传递一个子组件,可能会须要不少个「占位符」。例如在这个 Dialog
组件中,你不只须要自定义它的 body
,你但愿它的 header
和 footer
都是给 Dialog
组件的使用者自由定制。这种状况能够这样作:
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>
)
}
}
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>
)
}
}
复制代码
在咱们声明 Dialog
组件时,header
和 footer
部分咱们分别增长了 this.props.renderHeader
和 this.props.renderFooter
做为占位符。相应地,咱们在使用 Dialog
组件时,就能够给 renderHeader
和 renderFooter
传入 JSX 元素,这两个分别传入的 JSX 元素将会填充它们在 Dialog
组件中的位置——就像在 Dialog
JSX 标签里写入的内容,会填充到 this.props.children
的位置同样。
组件的组合须要遵照 this.props.children
的全部规则。组合这个功能和 this.props.children
同样是经过 slot
实现的,也就是说 this.props.children
的限制对于组件组合也都一样适用。
全部组合都必须用 render
开头,且遵照驼峰式命名法。和咱们的事件规范以 on
开头同样,组件组合使用 render
开头。
组合只能传入单个 JSX 元素,不能传入其它任何类型。当你须要进行一些条件判断或复杂逻辑操做的时候,可使用一个 Block
元素包裹住,而后在 Block
元素的里面填充其它复杂的逻辑。