使用 React + icejs 开发一个完整的 Todo 应用 - 小程序篇
icejs 主要应用场景为开发中后台应用。但 icejs@1.7.0 版本开始支持小程序开发。如果你想使用 React 同时开发中后台应用和小程序,那么 icejs 即可满足你。使用同一套技术体系,减少技术切换成本,提高研发效率。
介绍
本文将演示如何使用 icejs 构建 Todo 小程序 + 后台管理系统,同时包括相应服务端。
Todo 应用的功能或需求为:
- 小程序端:展示 Todo 列表,支持增删改查,以及同步数据到服务端。
- 后台管理系统:小程序用户信息和增删改查的管理系统。
整体的技术栈设计如下:
- 小程序
- icejs 框架
- universal-request 数据请求
- 后台管理系统
- icejs 框架
- icejs build-plugin-ice-auth 插件,权限管理
- fusion design UI 组件库
- 服务端 + 数据库
- eggjs 服务端框架
- egg-sequelize + mysql2 用于 eggjs 连接 MySQL 数据库
- MySQL 数据库
- uuid 唯一 id 生成
因篇幅较长,如何同时开发小程序+中后台应用(feat: icejs)将分为三篇分别介绍。
- 小程序篇(本文)
使用 icejs 开发 Todo 小程序。
- 后台管理系统篇
使用 icejs 开发 Todo 小程序后台管理系统。
f00bar:使用 React + icejs 开发一个完整的 Todo 应用 - 后台系统篇zhuanlan.zhihu.com- 服务端篇
搭建服务 Todo 小程序及后台管理系统的服务端。
f00bar:使用 React + icejs 开发一个完整的 Todo 应用 - 服务端篇zhuanlan.zhihu.com小程序
项目代码见:miniprogram-materials/scaffolds/todos 小程序开发基于icejs,详细内容见 icejs 小程序开发文档
项目初始化
创建文件夹存放代码
$ mkdir todos && cd todos
基于 icejs 小程序 JavaScript 模板初始化项目
$ npm init ice . # 在当前目录下初始项目
选择 JavaScript 小程序模板即 Lightweight JavaScript template with miniapp Program
启动项目
$ npm install && npm run start
# 从微信开发者工具中导入构建完成后的产物可以看到项目正常运行
# 构建产物位置位于 ./build 目录中。./build/miniapp 为支付宝小程序;./build/wechat-miniprogram 为微信小程序
微信开发者工具下载 支付宝小程序开发工具下载
使用微信开发者工具管理小程序
导入构建的小程序包
此处 AppID 应填写自己所申请的小程序 AppID 或使用 测试号
开发者工具中小程序编译成功
项目目录结构为:
.
├── .ice/ # 运行时生成的临时目录
├── build/ # 构建产物目录
├── src/ # 源码目录
│ ├── components # 应用的公共组件
│ │ └── Logo
│ │ ├── index.module.less # Logo 组件的样式文件
│ │ └── index.jsx # Logo 组件 JSX 源码
│ └── pages # 页面
│ │ └── Home # home 页面
│ │ └── index.jsx
│ ├── app.js # 应用入口文件
│ └── app.json # 应用配置,包括路由配置,小程序 window 配置等
├── README.md # 项目说明
├── build.json # 项目构建配置
├── package.json
└── tsconfig.json
页面编写
页面编写与使用 React 开发基本一致。
对于小程序中的生命周期函数,可使用 usePageShow
、usePageHide
或者 withPageLifeCycle
等方法进行监听。详细文档见页面配置#生命周期。
Todos 列表页
创建 src/pages/todos 编写 UI
import React, { useState } from 'react';
import { usePageShow } from 'ice';
import AddButton from '@/components/add-button'; // 组件:添加新 Todo按钮
import logo from '@/public/logo.svg';
import styles from './index.module.scss';
const Todos = () => {
// state
const [userInfo, setUserInfo] = useState({});
const [todos, setTodos] = useState([]);
// handlers
const onTodoChange = async id => {
let changedContent = {};
const changedTodos = todos.map(todo => {
const { id: curId } = todo;
const { completed } = todo.content;
if (id === curId) {
changedContent = {
...todo.content,
completed: id === curId ? !completed : completed
};
}
return {
...todo,
content: {
...todo.content,
completed: id === curId ? !completed : completed
}
};
});
setTodos(changedTodos);
};
// lifecycle function
usePageShow(async () => {
const defaultTodos = [
{
content: { text: 'Learning Javascript', completed: true },
id: 0
},
{
content: { text: 'Learning ES2016', completed: true },
id: 1
},
{
content: { text: 'Learning 小程序', completed: false },
id: 2
},
]
// 暂时使用默认 Todos 测试 UI
setTodos(defaultTodos);
})
return (
<div className={styles['page-todos']}>
<div className={styles.user}>
<button type='