Frontend / Client Developer on an indie path | 前端 / 客户端开发者
I focus on frontend development and client-side product practice, with React Native project experience.
前端是当前重点,持续做客户端方向实践;有 React Native 项目经验。
让豆包出了点题来锻炼,学习 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 方法,通过箭头函数操作单个对象的内容。箭头函数 (数组中单个对象) => 函数/对象。 ...
Swift 结构体与 JSON 转换 创建结构体 1 2 3 struct Date: Decodable { // 类型名用大驼峰 PascalCase let code: Int // 变量名用小驼峰 camelCase } JSON 嵌套解析 JSON 解析支持嵌套,嵌套结构体即可。 示例 JSON: 1 2 3 4 5 6 7 { "code": 200, "data": { "title": "标题", "tags": ["新闻", "热点"] } } 对应的 Swift 结构体: 1 2 3 4 5 6 7 8 9 struct DataStruct: Decodable { // 大驼峰 let title: String let tags: [String] } struct Response: Decodable { // 大驼峰 let code: Int let data: DataStruct } 结构体初始化 1 2 3 4 5 6 7 8 9 struct DataStruct: Decodable { let title: String let tag: String init(title: String, tag: String) { self.title = title self.tag = tag } } 默认情况下,只有 let/var 时不用写 init 函数,可以直接使用。 ...
此下 TypeScript-JSX 代码皆是在 React Native 中进行使用,与 React(Web) 有出入,在此提醒。 一、useState 的基本使用 1 const [count, setCount] = useState(0) 定义一个 count 状态值,setCount 为 useState 传递的更新函数。 直接将 count 更新为传入的值。 搭配 Button 使用 1 <Button title="Count + 1" onPress={() => setCount(count + 1)} /> 这里使用了箭头函数,保证只有在点击时才触发 setCount 函数。 为什么需要使用箭头函数? 如果直接写成: 1 onPress={setCount(count + 1)} 那么在组件渲染阶段函数就会被立即执行,而不是在点击时执行。 二、关于渲染与 useState 的一些补充理解 React 在渲染时,并不是完全重新渲染整个界面,而是通过 Virtual DOM 进行比对,只对发生变化的部分进行更新(局部 fix)。 这一部分我目前还没有系统学习,只是在学习过程中了解到一些相关知识。同时也了解到: useState 和 useReducer 底层其实是同一套逻辑 useState 本质上是 useReducer 的一个特殊情况。 三、useState 底层实现的关键发现(源码/与 ai 的讨论) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 ### 核心发现 useState 本质上就是 useReducer 的特殊情况 三个关键阶段 #### 1. 初始挂载(mount) function mountState<S>(initialState): [S, Dispatch] { const hook = mountStateImpl(initialState) // 创建一个 hook 对象 const queue = hook.queue // 创建更新队列 const dispatch = dispatchSetState.bind(null, currentlyRenderingFiber, queue) queue.dispatch = dispatch return [hook.memoizedState, dispatch] // 返回 [状态值, 更新函数] } #### 2. 更新阶段(update) function updateState<S>(initialState): [S, Dispatch] { return updateReducer(basicStateReducer, initialState) // 调用 useReducer! } #### 3. Dispatcher 映射 const HooksDispatcherOnUpdate: Dispatcher = { // ... useState: updateState, // ... } #### 这说明了什么? | 你写的代码 | 实际运行 | | ------------- | ------------------------------------- | | `useState(0)` | `useReducer(basicStateReducer, 0)` | | `setCount(1)` | `dispatch({ type: null, action: 1 })` | #### basicStateReducer 是什么? function basicStateReducer<S>(state: S, action: S | ((S) => S)): S { return typeof action === 'function' ? action(state) : action } 你可以这样理解: - `setCount(1)` → 直接返回 `1` - `setCount(c => c + 1)` → 执行函数并返回新值 #### 这里体现的设计思想 1. **统一性**:useState 和 useReducer 底层逻辑统一 2. **多态**:不同渲染阶段使用不同的 dispatcher(mount / update / rerender) 3. **不可变性**:每次更新都会创建新的状态值,而不是修改旧值 再深入就是 Fiber 调度算法,这部分相对复杂,目前 AI 也没有建议我继续深入,我也暂时没有选择继续在这里消耗时间。 ...
好久没有坐在桌子前写写blog了,从十月初开始第一份实习,算是一种成长了,感觉认识了很多新的技术栈,接下来就打算继续深入学习客户端开发了,完成自己从小的梦想,做自己的app,通过学习技术解决自己的需求,同时上架app,看看是否能帮到大家,也算是一种价值体现吧。 有的时候不知道该写些什么,总是感觉没有内容可以写,但是每天想说的话又很多,时不时想想到底什么时候才能不天天为了以后的生计着急,以后能干什么,什么时候才能出人头地。 总是过的很着急,可是有时心中有时又会想到,成长的过程本身就是一个从量变到质变的过程,因为总是想一步就达到自己心中自己的样子。说实话,这也是我浮躁的原因。思来想去,沉下心来做,会耗费很多时间,而我又担心浪费时间,时刻再斟酌,做这件事情本身是不是有意义的,是不是不浪费时间,对我达到心中的自己是否有榜之,是否有价值。自从上次跟GPT聊了之后发现,其实自己的能力还是很弱,渴望一步就获得别人29-30岁的成就,这怎么可能。同时我也不再每天坐在电脑前敲代码7-9小时了,我试着跑步,练习英语,还有写写blog,练习自己的表达能力。我觉得只要我去做了,能改变我的,这些都是有意义的,之前的坐在那里7-9小时,对身体的伤害太大了,我觉得这太消耗人的心气了,慢慢的我就变为工具人了,我也反思自己,如果我只会敲代码,我还会干什么?所以这也是我发布在抖音和blog的原因。记录一下自己的成长,也同时练习自己的表达能力。 我个人认为表达能力这个东西我觉得真的很重要,在你讲给别人的时候,表达能力让你能表达的更清晰,别人也能更清晰的理解你的描述,你能更清晰的表达你的心中所想,别人也能更清晰的理解你的心中所想。提高沟通效率。如上,我不知道有多少人能看到这里,上卖弄的表述我觉得其实不是很好,我是想到什么说什么,这样的话就很难留住人,锻炼表达能力的原因还有一个就是为了能让我的文字,更能够渲染情绪吧?让我的想法能更好的表达出来,让同频的人驻足,至少,一眼看过去不是不想读。
碎知识 包在被导入时,会默认执行 init 的函数,如果有多个,会按照字典序执行。 接口配置 通过路由组的实例,来进行一个路由端点的定义 比如 apiRouter.GET("/status", controller.GetStatus) 定义一个 /status 并且设置了一个激活函数,必须是 func(\*Context) 传入上下文(类似中间件) 函数内部通过 c.JSON(http.StatusOK, gin.H{} 返回状态码,以及 json 序列化数据 一个简单请求 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package main import "github.com/gin-gonic/gin" func main() { server := gin.New() // 定义一个路由端点 GET 请求 server.GET("/", func(c *gin.Context) { // gin.H 来创建 JSON 响应数据 // 通过 c.JSON() 发送给客户端 c.JSON(200, gin.H{ "message": "Hello, Gin!", "status": "success", }) }) // 启动服务器 // server.Run() 默认监听 8080 端口 server.Run(":8080") } 身份认证中间件 authHelper 辅助函数 首先通过会话 session 来进行判断用户的基础身份 通过上下文获取请求会话实例,通过会话实例获得用户的基础信息 ...