Taro Library
Taro + Redux + 本地 Mock Server 微信小程序示例项目
Install / Use
npx skills add imageslr/taro-libraryInstalls into whichever agent you are using.
README
项目简介
本项目是在线借书平台小程序使用 Taro 重构后的版本,仅包含三个示例页面,非常简单。面向人群主要是 Taro/React/Redux 的初学者,目的是提供一个简单的实践项目,帮助理解 Taro 与 Redux 的配合方式与 Taro 的基本使用。本项目还提供了一个快速搭建本地 mock 服务的解决方案。
因为我也是刚接触 Taro/React,所以只是分享一些开发经验,绕开一些小坑。如果觉得不错的话,请点右上角“⭐️Star”支持一下我,谢谢!如果有问题,欢迎提 issue;如果有任何改进,也欢迎 PR。
扫码体验:

技术栈
Taro + Taro UI + Redux + Webpack + ES6 + Mock
项目截图

目录
运行项目
本项目在以下环境中编译通过:taro v1.2.20、nodejs v8.11.2、微信开发者工具最新版。
首先需要安装必要的环境:
# 安装 nvm,已经安装请忽略
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash
# 安装 nodejs v8.11.2
nvm install v8.11.2
# 切换 node 版本
nvm use v8.11.2
# 检查 node 版本
node --version
## 安装 taro
npm install -g @tarojs/cli@1.2.20
克隆项目:
git clone https://github.com/imageslr/taro-library.git
cd taro-library
启动小程序:
# 安装依赖
npm install // 或者 yarn
# 编译小程序
npm run dev:weapp
启动 mock 服务 (新建一个终端,在项目根目录下执行):
cd simplest-mock-server
npm install
gulp mock
之后在微信开发者工具中导入项目,即可预览。
开始学习
Taro 简介
Taro 是一个遵循 React 语法规范的多端开发解决方案。最近想学习 React,于是就想到使用 Taro 重构很早之前开发的在线借书平台小程序。虽然 Taro 上手有一定难度,但是其 React 框架比小程序原生更为灵活与规范,给我带来了非凡的开发体验。
在正式开始之前,您必须对 Taro 框架、 React 语法与小程序框架有一定的了解。此外,我建议您阅读以下文档,会更容易上手:
- Taro 官方文档:必读,开发时也会随时查阅
- Taro UI 官方文档:推荐,本项目使用 Taro UI 作为 UI 组件库
- React 官方文档:必读,掌握 React 语法的必经之路,读完 MAIN CONCEPTS 部分就差不多了。对应的中文文档在这里,与英文版略有区别
- Redux 文档:推荐,Redux 是最经常与 React 搭配使用的状态管理库。不过这个文档过于详实,读起来比较费劲,推荐你掌握 Redux 三大概念(Action、Reducer、Store)后直接在实践中体会 Redux 的原理与作用
- React.js 小书:推荐,一步步从零构建 React 与 Redux,非常好的入门教程
- Mock.js 文档:推荐,速查模拟数据占位符与模板
开发工具
开发工具:VS Code
代码规范:Prettier 插件 + ES Lint 插件
VS Code 对 JSX 与 TypeScript 有天然的支持,使用 VS Code 开发 Taro,不需要配置任何插件就能实现 Taro 组件的自动 import 与 props 提示,非常方便。
代码格式化插件我选择 Prettier,它屏蔽了很多配置项,强制遵循约定的规范。与之类似的格式化插件还有 Beautify,不过我更喜欢 Prettier 对 JSX 属性强制自动换行的风格。
ES Lint 是 JavaScript 与 JSX 的静态检测工具,安装 ES Lint 插件后在代码编写阶段就可以检测到不易发现的错误(如为常量赋值、变量未使用、变量未定义等等)。Taro 已经定义了一套 ES Lint 规则集,使用 taro-cli 生成的 Taro 项目基本不需要再作额外配置。
样式规范
CSS 预处理器
Taro UI 定义了很多变量与可复用的 mixins。为了与 Taro UI 样式风格保持一致,本项目采用 Taro UI 所使用的 Sass 作为 CSS 预处理器。
布局
优先使用 Flex 布局。学习 Flex 布局可以参考这两篇文章:
Taro UI 封装了一些常用的 Flex 样式类,包括:
- 1~12 的栅格化长度类
at-col-1、at-col-2等 - 栅格化偏移类
at-col__offset-1等 flex属性:超出换行at-row--wrap,宽度根据内容撑开at-col--auto- 对齐方式、排列方式
不过 Taro UI 并没有为flex: none;提供样式类。
BEM 命名规范
关于 BEM,网上有很多的教程,就不再细说了。Block__Element--Modifier的命名方式在 Sass 中很容易描述:
.block {
//...
&__element {
//...
&--modifier {
//...
}
}
}
组件样式
对于/components目录下的可复用组件,使用my作为命名空间,避免被全局样式污染,比如my-panel、my-search-bar等。
组件可以使用externalClasses定义若干个外部样式类,或者开启options.addGlobalClass以使用全局样式。见Taro 文档 - 组件的外部样式和全局样式。
如果希望能够在组件的props中直接传递className或者style,比如这样:
// index.jsx
<MyComponent className='custom-class' style={/* ... */}>
Taro 默认并不支持这一写法。我们可以将className和customStyle作为组件的props,然后在render()中手动将这两个props添加到根元素上:
// my-component.jsx
export default MyComponent extends Component {
static options = {
addGlobalClass: true
}
static defaultProps = {
className: '',
customStyle: {}
}
render () {
const { className, customStyle } = this.props
return <View
className={'my-class ' + className}
style={customStyle}
>
组件内容
</View>
}
}
尺寸单位
Taro 的尺寸单位是px,默认的尺寸稿是 iPhone 6 750px。Taro 会 1:1 地将px转为小程序的rpx。而在小程序中,px与rpx是 1:2 的关系。如果希望字体采用浏览器的默认大小14px,那么应该这么写:
- Taro:
28px - Taro:
14PX - Taro JSX 行内样式:
Taro.pxTransform(14) - 小程序原生:
28rpx
Taro 会将有大写字母的Px或PX忽略,但是 VS Code 在使用 Prettier 插件时会自动将Px或PX转为px。对于这个问题,有两种解决方案:
- 换用 Beautify 插件
- 在包含大写字母的属性的前一行添加
/* prettier-ignore *//* prettier-ignore */ $input-padding: 25PX;
项目初始化
$ taro init taro-library
> ...
> ? 请输入项目介绍! Taro图书小程序
> ? 是否需要使用 TypeScript ? No
> ? 请选择 CSS 预处理器(Sass/Less/Stylus) Sass
> ? 请选择模板 Redux 模板
>
> ✔ 创建项目: taro-library
安装项目依赖:
$ npm install taro-ui --save
引入 Redux
Redux 文件设置
在初始化的时候,我们选择了 Redux 模板。打开文件夹,可以看到 Taro 创建了一个示例页面,redux 相关的文件夹为:
├── actions
│ └── counter.js
├── constants
│ └── counter.js
├── reducers
│ ├── counter.js
│ └── index.js
└── store
└── index.js
这种方式是按照 Redux 的组成部分来划分的,/constants是action-type字符串的声明文件,不同文件夹中的同名文件对应同一份数据。
另一种划分方式是将同一份数据的所有文件组合在同一个文件夹里:
└── store
├── counter
│ ├── action-type.js // 对应/constants/counter.js
│ ├── action.js // 对应/actions/counter.js
│ └── reducer.js // 对应/reducers/counter.js
├── home
│ ├── action-type.js
│ ├── action.js
│ └── reducer.js
├── index.js // 对应/store/index.js
└── rootReducer.js // 对应/reducer/index.js
本项目采用第二种方式管理 Redux 数据。Taro 生成的 Redux 模板中已经添加了redux-logger中间件实现日志打印功能。
代码见 dev-redux-init 分支。
connect 方法
推荐先阅读 Redux 文档。
使用 Redux 之后,我们可以将数据存储在store中,通过action操作数据。那么怎么在组件中访问与操作数据呢?react-redux提供了connect方法,允许我们将store中的数据与action作为props绑定到组件上。
从原理上来讲,connect方法返回的是一个高阶组件。这个高阶组件会对原组件进行包装,然后返回新的组件。不过我们这里不讲connect的细节,只讲它的使用方法。有关connect方法与 Redux 的原理,推荐阅读 React.js 小书。
参数
connect接收四个参数,分别是mapStateToProps、mapDispatchToProps、mergeProps和options。本项目只用到了前两个参数。
mapStateToProps
mapStateToProps是一个函数,它将store中的数据映射到组件的props上。mapStateToProps接收两个参数:state、ownProps。第一个参数就是 Redux 的store,第二个数据是组件自己的props。
举个例子:
const mapStateToProps = (state) => {
return {
count: state.count
}
}
这段代码的功能是将store中的count属性的值,映射到组件的 this.props.count 上。当我们访问this.props.count时,输出的就是store.count的值。当store.count值变化时,组件也会同步更新。
我们还可以使用 ES6 的对象解构赋值、属性简写和箭头函数等语法,进一步简化上面的代码:
const mapStateToProps = ({ count }) => ({
count
});
有时候我们需要根据组件自身的props作一些条件判断,这时候就需要用到第二个参数。
mapDispatchToProps
mapDispatchToProps也是一个函数,它接收两个参数:dispatch、ownProps。第一个参数就是 Redux 的dispatch方法,第二个数据是组件自己的props。它的功能是将action作为props绑定到组件上。
举个例子:
import { add, minus, asyncAdd } from "@store/counter/action";
const mapDispatchToProps = (dispatch) => {
return {
add() {
dispatch(add());
},
dec() {
dispatch(minus());
},
asyncAdd() {
dispatch(asyncAdd());
}
}
}
当我们调用this.props.add时,实际上是在调用dispatch(add())。
使用 connect 方法
使用connect方法将组件与 Redux 结合:
import { add, minus, asyncAdd } from "@store/counter/action";
// 首先定义组件
class MyComponent extends Component {
render() {
return;
<View>
<Button onClick={this.props.add}>点击 + 1</Button>
<View>计数:{this.props.count}次</View>
</View>;
}
}
// 定义 mapStateToProps
const mapStateToProps = ({ count }) => ({
count
});
// 定义 mapDispatchToProps
const mapDispatchToProps = dispatch => {
return {
add() {
dispatch(add());
}
};
};
// 使用 connect 方法,export 包装后的新组件
export connect(mapStateToProps, mapDispatchToProps)(MyComponent);
这种分散的写法不利于我们查看组件从 Redux 中引入了多少props。我们可以使用 ES6 的装饰器语法进一步改造它:
import { add, minus, asyncAdd } from "@store/counter/action";
@connect(
({ counter }) => ({
counter
}),
dispatch => ({
add() {
dispatch(add());
}
})
)
class MyComponent extends Component {
render() {
return;
<View>
<Button onClick={this.props.add}>点击 + 1</Button>
<View>计数:{this.props.count}次</View>
</View>;
}
}
export default MyComponent;
我们甚至可以使用对象形式来传递mapDispatchToProps,获得更简化的写法:
@connect(
({ counter }) => ({
counter
}),
{
// 调用 this.props.dispatchAdd() 相当于
// 调用 dispatch(add())
dispatchAdd: add,
dispatchMinus: minus,
// ...
}
)
这就是 Taro 组件与 Redux 结合的最终形式。
异步 Action
异步 Action 返回的是一个参数为dispatch的函数,这个函数本身也可以被dispatch。我们只需要在 Redux 中
Related Skills
node-connect
385.5kDiagnose OpenClaw Android, iOS, or macOS node pairing, QR/setup code, route, auth, and connection failures.
blender-python-addon
40.5kBlender Python add-on rules for operators, panels, properties, registration, testing, and API-safe scripting
flutter-development-guidelines-cursorrules-prompt-file
40.5kCursor rules for Flutter development with MVVM architecture, Riverpod state management, Material widgets, and Dart style guidelines.
commit-push-pr
140.7kCommit, push, and open a PR
