起因
起因
一直有支付宝、微信账单导出并统一管理的想法
React或NextJs又是想学又从未开始的技术栈
这几天准备尝试通过从0做一个账单管理功能,遇到不懂的再查资料。
准备开发的核心功能非常简单:
- 支付宝、微信excel账单导入并解析
- 支持读取邮箱并导入
- 支持部分消费记录隐藏
- 支持对消费记录的分类进行手动管理
从模板开始
steven-tey/precedent是一个比较流程的nextjs模板,start也比较多。
clerk
模板继承了clerk
, 一个全面的用户管理平台,具有设计精美的嵌入式 React 组件。
启动项目后按提示操作即可:
- 创建.env.local文件,设置好从clerk申请的KEY
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
CLERK_SECRET_KEY=
NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL=/
NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL=/
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
CLERK_SECRET_KEY=
NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL=/
NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL=/
项目结构
├── 📁.next //Next.js 的构建输出目录
// 此目录是 Next.js 13 及以上版本的一个新特性,用于构建应用。
// 包含应用的路由和页面(如 `page.js`、`layout.js`)结构。
// 支持文件系统路由和 React 服务器组件。
├── 📁app
├── 📁components // 用于存放可复用的 React 组件
// 存放应用逻辑或辅助功能的目录。可以包含 API 调用、数据库访问、数学函数等共享逻辑。
├── 📁lib
├── 📁public
// 程序run的时候自动创建,本项目里这个默认被.gitignore忽略
// 它的主要目的是增强 Next.js 项目中的 TypeScript 支持,确保 Next.js 的类型定义能够被正确引入和使用。默认自动引用了next 和 next/types/global
├── next-env.d.ts
├── next.config.js// Next.js 项目的配置文件
├── node_modules
├── package.json
├── pnpm-lock.yaml
├── postcss.config.js // PostCSS 插件的配置
├── prettier.config.js // 配置 Prettier 工具的格式化规则
├── robots.txt
├── tailwind.config.js
└── tsconfig.json // ts 的配置文件
├── 📁.next //Next.js 的构建输出目录
// 此目录是 Next.js 13 及以上版本的一个新特性,用于构建应用。
// 包含应用的路由和页面(如 `page.js`、`layout.js`)结构。
// 支持文件系统路由和 React 服务器组件。
├── 📁app
├── 📁components // 用于存放可复用的 React 组件
// 存放应用逻辑或辅助功能的目录。可以包含 API 调用、数据库访问、数学函数等共享逻辑。
├── 📁lib
├── 📁public
// 程序run的时候自动创建,本项目里这个默认被.gitignore忽略
// 它的主要目的是增强 Next.js 项目中的 TypeScript 支持,确保 Next.js 的类型定义能够被正确引入和使用。默认自动引用了next 和 next/types/global
├── next-env.d.ts
├── next.config.js// Next.js 项目的配置文件
├── node_modules
├── package.json
├── pnpm-lock.yaml
├── postcss.config.js // PostCSS 插件的配置
├── prettier.config.js // 配置 Prettier 工具的格式化规则
├── robots.txt
├── tailwind.config.js
└── tsconfig.json // ts 的配置文件
三方库
列举模板中用到的三方库
classnames
A simple JavaScript utility for conditionally joining classNames together.
At its core, “classnames” is a lightweight JavaScript library that helps manage CSS classes in a more intuitive and organized manner.
It’s particularly popular in the React ecosystem for handling dynamic class names. Instead of concatenating class names or using complex conditional logic to toggle them, “classnames” simplifies the process, making your code cleaner and more efficient.
原始代码:
const buttonClasses = `btn ${isActive ? 'active' : ''} ${isDisabled ? 'disabled' : ''}`;
const buttonClasses = `btn ${isActive ? 'active' : ''} ${isDisabled ? 'disabled' : ''}`;
使用classNames
简化:
import classNames from 'classnames';
const buttonClasses = classNames('btn', {
active: isActive,
disabled: isDisabled,
});
import classNames from 'classnames';
const buttonClasses = classNames('btn', {
active: isActive,
disabled: isDisabled,
});
clsx
A tiny (239B) utility for constructing
className
strings conditionally.
和 classnames
相似。
import clsx from 'clsx';
// or
import { clsx } from 'clsx';
// Strings (variadic)
clsx('foo', true && 'bar', 'baz');
//=> 'foo bar baz'
// Objects
clsx({ foo:true, bar:false, baz:isTrue() });
//=> 'foo baz'
// Objects (variadic)
clsx({ foo:true }, { bar:false }, null, { '--foobar':'hello' });
//=> 'foo --foobar'
// Arrays
clsx(['foo', 0, false, 'bar']);
//=> 'foo bar'
// Arrays (variadic)
clsx(['foo'], ['', 0, false, 'bar'], [['baz', [['hello'], 'there']]]);
//=> 'foo bar baz hello there'
// Kitchen sink (with nesting)
clsx('foo', [1 && 'bar', { baz:false, bat:null }, ['hello', ['world']]], 'cya');
//=> 'foo bar hello world cya'
import clsx from 'clsx';
// or
import { clsx } from 'clsx';
// Strings (variadic)
clsx('foo', true && 'bar', 'baz');
//=> 'foo bar baz'
// Objects
clsx({ foo:true, bar:false, baz:isTrue() });
//=> 'foo baz'
// Objects (variadic)
clsx({ foo:true }, { bar:false }, null, { '--foobar':'hello' });
//=> 'foo --foobar'
// Arrays
clsx(['foo', 0, false, 'bar']);
//=> 'foo bar'
// Arrays (variadic)
clsx(['foo'], ['', 0, false, 'bar'], [['baz', [['hello'], 'there']]]);
//=> 'foo bar baz hello there'
// Kitchen sink (with nesting)
clsx('foo', [1 && 'bar', { baz:false, bat:null }, ['hello', ['world']]], 'cya');
//=> 'foo bar hello world cya'
eslint调整为允许设置any: ESLint: Unexpected any. Specify a different type.(@typescript-eslint/no-explicit-any)