当前位置: 首页 > news >正文

observer pattern 最简上手笔记

先说痛点:我在做 React 项目时,最怕「一个组件里的交互影响到五六个毫不相干的兄弟组件」。早期我把 setState 一层层传下去,结果 props 里飘满了 callback,组件拆一半就得全重写。后来我用了 observer 模式,代码瞬间清爽。

我先踩过的坑

  • 把逻辑全写在父组件,state 和 UI 绑死,改需求就得全部重写
  • 用 Context Provider 绕大圈,render 频繁触发,写起来像套娃
  • 忘掉 off/unsubscribe,切一次路由就内存泄露,Chrome Memory 里一片红

现在我直接三步解决

  1. 先写一个轻量 observable(就 30 行)
// Observable.ts
export default class Observable<T = any> {private observers: Array<(data: T) => void> = []subscribe(fn: (data: T) => void) {this.observers.push(fn)// 顺手返回一个解绑函数,免得我忘了return () => {this.observers = this.observers.filter((o) => o !== fn)}}unsubscribe(fn: (data: T) => void) {this.observers = this.observers.filter((o) => o !== fn)}notify(data: T) {this.observers.forEach((observer) => observer(data))}
}
  1. 组件里只管「触发」和「监听」
// App.tsx
import observable from './Observable'
import { toast } from 'react-toastify'const logger = (msg: string) => console.log(Date.now(), msg)
const toastify = (msg: string) => toast(msg, { position: 'bottom-right', autoClose: 2000 })export default function App() {React.useEffect(() => {// 组件加载时一次性注册const offLog = observable.subscribe(logger)const offToast = observable.subscribe(toastify)return () => {// 卸载时解绑,不留后患offLog()offToast()}}, [])const handleClick = () => observable.notify('按钮被点')const handleToggle = () => observable.notify('开关切了')return (<><button onClick={handleClick}>点我</button><input type="checkbox" onChange={handleToggle} /></>)
}

要点:把 subscribe 丢进 useEffect,返回的清理函数里解绑,永远不会内存泄露。

  1. 需求再多,也只需「加订阅」——组件代码零改动
    想再发埋点?
const track = (msg) => fetch('/analytics', { method: 'POST', body: msg })
observable.subscribe(track)  // 一行搞定,不改任何旧组件

扩展阅读

  • RxJS:把上面的小玩具换成 RxJS,可处理异步流、节流、防抖、合并事件等高阶需求
    典型代码:
import { fromEvent, merge } from 'rxjs'
import { mapTo, sample } from 'rxjs/operators'merge(fromEvent(document, 'mousedown').pipe(mapTo(false)),fromEvent(document, 'mousemove').pipe(mapTo(true))
).pipe(sample(fromEvent(document, 'mouseup'))).subscribe((isDragging) =>console.log('刚才拖动了吗?', isDragging))

一句话总结:把「变化来源」和「响应动作」彻底解耦,代码像乐高,需求再多也能拼。

http://www.xdnf.cn/news/1401157.html

相关文章:

  • 如何调整Linux系统下单个文件的最大大小?
  • hadoop安欣医院挂号看诊管理系统(代码+数据库+LW)
  • 2025年高性能计算年会
  • centos7.9的openssh漏洞修复脚本
  • w嵌入式分享合集125
  • 【Day 33】Linux-MySQL 备份与恢复详解
  • 【机器学习入门】3.3 FP树算法——高效挖掘频繁项集的“树状神器”
  • SNMPv3开发--简单使用
  • bevformer模型训练过程
  • 嵌入式Linux输入子系统驱动开发
  • Python实现点云AABB和OBB包围盒
  • 后台技术方案设计经验之谈
  • FPGA增量式方差与均值计算
  • 银河麒麟V10(Phytium,D2000/8 E8C, aarch64)开发Qt
  • 【计算机网络】生产问题排查:如何使用Wireshark抓包/读取抓包文件进行网络分析
  • TensorFlow深度学习实战(35)——概率神经网络
  • SpringCloud Alibaba Sentinel 流量治理、熔断限流(四)
  • (三)Python语法基础(实战)
  • 为什么要用 Markdown?以及如何使用它
  • 【系列09】端侧AI:构建与部署高效的本地化AI模型 第8章:移动端部署实战 - Android
  • SQLSugar 封装原理详解:从架构到核心模块的底层实现
  • C++ 面试高频考点 力扣 34. 在排序数组中查找元素的第一个和最后一个位置 二分查找左右端点 题解 每日一题
  • PostgreSQL表空间(Tablespace)作用(管理数据库对象的存储位置)(pg_default、pg_global)
  • 一道比较难的sql题,筛选出重复字段的行数
  • 【物联网】bleak (scan)扫描在干什么? BLE 广播(Advertising)
  • jxWebUI--下拉选择框
  • AtCoder Beginner Contest 421
  • 海盗王64位dx9客户端修改篇之三
  • React前端开发_Day10
  • 骑行商城怎么开发