Wang Xu

Frontend / Client Developer on an indie path | 前端 / 客户端开发者

I focus on frontend development and client-side product practice, with React Native project experience.

前端是当前重点,持续做客户端方向实践;有 React Native 项目经验。

Resume/简历GitHub

Drizzle + SQLite + Zod 学习笔记

一、schema.ts 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'; import { createInsertSchema, createSelectSchema } from 'drizzle-zod'; export const rnlearnTodos = sqliteTable('rnlearn_todos', { id: integer('id', { mode: 'number' }).primaryKey({ autoIncrement: true }), content: text('content').notNull(), createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(), }); export const insertRnlearnTodoSchema = createInsertSchema(rnlearnTodos); export const selectRnlearnTodoSchema = createSelectSchema(rnlearnTodos); export type RnlearnTodo = typeof rnlearnTodos.$inferSelect; export type NewRnlearnTodo = typeof rnlearnTodos.$inferInsert; 主角 drizzle-orm/sqlite-core drizzle-zod drizzle-orm/sqlite-core 是 Drizzle ORM 针对 SQLite 做的 core 包,类似于驱动。 drizzle-zod 是 Drizzle 做的辅助工具包,可以使用到 zod,专门为了对接 zod。 能生成 zod 校验规则,数据库 → 校验,保证单一数据规则来源。 sqliteTable sqliteTable:创建数据库表。 1 sqliteTable("数据库真实表名", { 字段配置 }) 字段配置就是类似对象。 通过 drizzle-orm/sqlite-core 给定的可以定义的类型,来给定结构。 ...

April 26, 2026 · 3 min · Wang Xu

Zod API 初入茅庐

一、 Zod 导入z后,可以通过 z.string() 字符串 z.number() 数字 z.email() 邮箱格式 z.enum([]) 枚举,类似于 | 限制字符串只能其中的选项 二、z.object() 创建 schema 通过z.object()可以创建schema 1 2 3 4 5 6 const UserSchema = z.object({ id: z.number(), name: z.string(), email: z.email(), active: z.boolean(), }); 三、z.infer() 通过 schema 获取类型 通过schema可以去获取到type类型, 如通过 z.infer<typeof UserSchema> 1 type User = z.infer<typeof UserSchema>; 可以获取到通过z.object创建的schema的数据形状。 schema 写完以后,类型可以直接推出来,不用自己再手写一遍 type 。 四、parse() 通过 schema 校验对象类型 1 2 3 4 5 6 7 8 const user_eg = { id: 1, name: 'Alice', email: 'xxxx@xxx.com', active: true, } const user = UserSchema.parse(user_eg); 如果 user_eg 是正确的,那么值将被赋给 user,经过了校验,类型是正确的。 如果格式不正确直接报错,直接抛 ZodError。 ...

April 24, 2026 · 2 min · Wang Xu

JavaScript 学习笔记:闭包与循环陷阱

一、奇怪的发现 循环打印为什么不是 0、1、2,而是 3、3、3? 1 2 3 4 for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0); } // 输出:3 3 3 原因: for 循环是同步执行,setTimeout 会等同步代码结束后再执行。闭包拿到的不是当时的值,而是 i 这个变量的引用。等回调真正执行时,循环已经结束了,i 也已经变成 3 了,所以结果就是 3、3、3。 二、闭包是什么 1 2 3 4 5 6 7 8 function test() { let a = 1; return () => { console.log(a); } } const fn = test(); fn(); // 输出 1 闭包是什么? 闭包可以理解成:函数 + 它能访问到的作用域 不一定非得是箭头函数,普通函数也一样 只要函数用了外部变量,闭包基本就出现了 只要返回出去的函数还在用这些变量,这些变量就不会被立刻释放 三、经典例子 例子1:计数器 1 2 3 4 5 6 7 8 9 10 11 function counter() { let cnt = 0; return () => { console.log(cnt); cnt++; } } const fn = counter(); fn(); // 0 fn(); // 1 fn(); // 2 解释: cnt 本来应该随着函数执行结束被释放,但返回出去的函数还在用它,所以它会一直保留下来。每次调用,都是在上一次的基础上继续加。 ...

March 21, 2026 · 2 min · Wang Xu

React 学习记录:map 渲染、受控组件与函数式更新

通过 map 生成组件 1 2 const todos = ['学习React', '写博客', '买咖啡', '运动'] <ul>{todos.map((todo)=>(<li key={todo}>{todo}</li>))}</ul> 可以通过 map 函数来渲染多个列表,比如这里渲染了四个 todo 列表。 通过数组的 map 方法来实现循环,并且使用箭头函数传递单个 todo,使用单个 todo 作为 key 及其值。循环过程中,会渲染四个 li。 受控组件 这里仅介绍 <select> 和 <input>,通过 值绑定属性 和 事件处理属性,实现 React 状态和表单组件值的实时同步,让用户输入或选择的内容能够实时更新到 React 的状态里。 通过 onChange 事件监听用户输入,当用户输入或选择选项时,这个事件会被触发。在事件处理函数中使用 useState 更新 React 的状态,而 value 显示 React 的状态值,实现界面值与 React 状态的实时同步。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import { useState } from 'react'; function TodoInput() { const [content, setContent] = useState(''); const [type, setType] = useState('work'); return ( <div> <input value={content} onChange={(e) => setContent(e.target.value)} placeholder="输入内容" /> <select value={type} onChange={(e) => setType(e.target.value)}> <option value="work">工作</option> <option value="life">生活</option> </select> </div> ); } 函数式更新 ...

March 6, 2026 · 2 min · Wang Xu

JavaScript 数组方法练习:map/filter/reduce/flat

让豆包出了点题来锻炼,学习 map/filter/reduce/flat。 map 方法,对 Array[] 实现遍历操作,过程中可通过箭头函数执行操作,得到操作后的新对象或者进行计算操作。 filter 方法,常用于过滤操作,选出符合规则的对象。 reduce,累加、数值计算、统计等。 flat,将嵌套对象 [[]] 展开为一维数组。 其中,map/filter/reduce 这三种方法在使用箭头函数时有「隐式返回」和「显式返回」两种写法。我在代码中也有明确的注释说明,如 map 方法第二题使用两种方式。在我上方的代码中,几乎都是隐式返回;不过在使用 reduce 时,返回对象使用了显式返回。 隐式返回 隐式返回,顾名思义,我们在箭头函数中不需要明确的写 return,() => (对象) 这种是返回一个对象,内部直接是一个键值。例如(行77-80): 1 products.map((t) => (对象)) 这种情况最终返回 [{}] 这种数据结构。 通过 filter 再次举例:需要筛选类别和折扣后价格的产品,返回筛选后的数组对象: 1 products.filter((t) => t.category == '数码配件' && t.price * t.discount < 300) 直接返回当前的布尔值。不需要 return。 显式返回 有隐式当然有显式。显式返回,必须写 return 控制返回内容,否则会返回 undefined。 在 map 中,箭头函数后方跟函数体,如 .map((t) => {函数体}),花括号中可以编写函数逻辑,通过 return 来控制返回内容。可以是对象、值等。 例如(行69-74): 1 products.map((t) => { return 对象 }) 可以在 return 前编写函数逻辑。 map 方法 map 方法,遍历数组,添加/删除/修改对应的键值,或构建新的对象。 数组后使用 .map 使用 map 方法,通过箭头函数操作单个对象的内容。箭头函数 (数组中单个对象) => 函数/对象。 ...

February 24, 2026 · 6 min · Wang Xu