展望2025:React状态管理该如何进行技术选型?

React从基础入门到高级实战:React 高级主题 - React设计模式:提升代码架构的艺术 本文深入探讨React高级设计模式,包括HOC、Render Props和Compound Components等核心架构方案。HOC模式通过函数封装实现逻辑复用,适用于认证和数据获取等场景;Render Props提供灵活的UI组合控制,适合动态渲染和表单验证;Compound Components通过状态共享构建协同组件,如Tabs和Dropdown等复合UI。分析各模式的优缺点,HOC可能导致嵌套问题,Render Props具有更高灵活性但增加复杂性,Compound Components模仿HTM 阅读详情


本文深度解读了Nadia Makarevich关于“React State Management in 2025: What You Actually Need”一文的核心思想。作者Nadia对React生态中经久不衰的“状态管理”议题提出了独到见解,并为2025年的React应用构建者描绘了一幅更务实的策略蓝图。她采取了一种“反主流”的立场,挑战了过去那种将所有状态尽数纳入Redux等单一库的传统模式,认为这种做法在许多现代场景中已显陈旧。她的核心论点在于:对“状态”进行精细化分类,并为每一类匹配最适宜的处理工具。

状态类型、挑战与推荐方案

状态类型

常见挑战 / 特性

推荐的处理方式 / 库

说明

远端状态 (Remote State)

从后端服务(如API、数据库)获取数据,涉及缓存管理、请求去重、错误处理、数据刷新、并发控制、乐观更新等复杂逻辑。

采用专门的数据获取与管理库,例如 TanStack Query (原React Query) 或 SWR。

这类工具提供了成熟的数据请求、缓存、重试、失效判断及分页等全套解决方案,远比手动实现更为稳健高效。

URL状态 / 查询参数

许多UI状态(如标签页切换、分页信息、筛选条件、面板显隐)被持久化到URL查询参数中,并要求与UI进行双向同步。

当路由库本身对查询参数的支持不足时,可以借助如 nuqs 这样的库来管理。

此举可以有效规避手动编写同步逻辑时可能引入的潜在缺陷和过高复杂度。

本地状态 (Local State)

仅在单一组件内部使用的状态,如模态框的开关、表单输入值、元素的显示与隐藏等。

直接运用React内置的 useState / useReducer Hooks即可。

将这类纯粹的本地状态提升至全局管理库,是毫无必要的,只会徒增应用的复杂度与依赖。

共享状态 (Shared State)

当多个不存在直接父子关系或层级相距甚远的组件需要共同读取和修改某份状态时。

优先考虑 Prop Drilling (状态提升) 或 React Context。仅当这些原生方案无法满足需求时,才考虑引入专门的状态管理库。

作者特别提醒:当状态逻辑变得复杂或状态数量增多时,Context容易引发“Providers地狱”和不必要的组件重渲染等问题。

基于以上分类,作者阐述了她在状态管理库选型上的标准与个人偏好。她强调,只有在妥善处理了远端状态、URL状态和本地状态之后,所剩余的那一小部分真正的“共享状态”,才是状态管理库大显身手的领域。

在权衡各类共享状态方案时,她列举了以下几项关键考量因素:

  • 简洁性 (Simplicity):库的API应直观易懂,上手门槛低,不应引入过于抽象的概念或全新的编程范式。

  • 避免Provider嵌套地狱:理想的方案应至多只有一个全局Provider,甚至无需Provider。

  • 精准更新:组件若只订阅了状态的某个切片,当该切片未发生变化时,组件不应被触发更新。

  • 与React生态的契合度:应与React的最新理念(如Hooks、单向数据流)保持一致,并良好兼容SSR/Server Components等新特性。

  • 社区健康度:库的社区活跃度高,且有可靠的维护支持。

通过这些标准进行筛选,作者认为 Zustand 在绝大多数场景下都是一个极佳的选择(她个人的黄金组合是:TanStack Query + nuqs + Zustand)。但她也一再申明,这仅是其个人偏好,而非放之四海而皆准的“银弹”。

文章结尾,她给出了一个精炼的总结:

  • 停止将所有状态都丢给单一的状态管理库。

  • 将不同类型的状态解耦,并交由最适合的工具去处理:

    • 数据获取/远端状态 → TanStack Query / SWR

    • URL查询参数状态 → 专用库 (如 nuqs)

    • 本地状态 → React原生Hooks (useState / useReducer)

    • 共享状态 → 仅在Context力有不逮时,才引入状态管理库。

  • 不存在所谓的“最佳”库。 你必须根据项目的实际需求来定义自己的评判标准,并据此做出最合适的选型。


https://medium.com/@adevnadia/react-state-management-in-2025-what-you-actually-need-a138da90dbec



如果你关注我的博客已有年月,大概会发现我鲜少涉足“观点输出”型文章。我创作的内容大多聚焦于阐述事物的运作原理,这类题材留给主观看法发挥的余地本就不多。

但这次,情况有所不同!我时常收到关于状态管理的垂询,大家关心哪些库是上乘之选,以及何为最佳实践。面对这类议题,主观意见是无法回避的。

那么,当下我们该拥抱哪个库?是老牌劲旅Redux,还是后起之秀Zustand?抑或是另辟蹊径?为何不干脆只用Context呢?

所以,为了激发讨论,我先抛出我的核心论断:你可能一个都不需要!

如果你想探究其背后的缘由,请继续往下读——不过,我得先找个掩体,以防万一。😅

你为何要进行状态管理的技术选型?

所谓的最佳状态管理方案究竟为何物……但在回答这个问题之前,我们必须先反问一句:你为何想知道?

不,我是认真的。这个世界上根本不存在普适性的“最好”。一切决策都根植于具体的上下文,无一例外。(当然,冰淇淋是个特例,开心果味的无疑是顶峰。)

倘若你的动机仅仅是学习新技能以丰富履历,提升在求职市场上的竞争力,那么直接投身于最热门的那些库即可。诸如“State of React”之类的行业调查报告,会是你的绝佳向导。或者更功利一些——直接打开你心仪公司的招聘启事,搜罗其中频繁出现的库名称。

又或者,你可以选择更高阶的路径(或许是高阶中的高阶?🤔):深入研习React的核心概念与高级用法,例如其重渲染与协调(reconciliation)机制的深层原理。一旦你对这些底层知识了然于胸,所有状态管理库在你眼中将大同小异,它们不过是用略有差异的语法来诠释相同的核心理念。

如果你正在维护一个历史悠久且体量庞大的项目,并对现行的Redux状态管理方案心生不满,渴望引入更优的替代品,那么你同样无需去寻觅那个所谓的“最佳”库。在这种情境下,当务之急是精准定位当前方案究竟在哪些方面让你感到掣肘。

你最应避免的,就是用一个完全不同的范式去取代一个团队已然熟稔的工具。例如,试图用XState替换Redux来解决所谓的“Redux过于复杂”的问题。这不仅需要巨大的团队培训成本,最终还可能无法兑现你解决问题的承诺。

或许你还觉得现有的状态管理库性能欠佳,希望找到性能更卓越的替代方案。那么,在这种情况下……问题的根源真出在库本身吗?你对此有多大的把握?请用量化的数据来支撑你的论断。因为我几乎可以断言,库本身对性能的拖累微乎其微。更普遍的情形是,症结在于未经优化的重渲染逻辑,或是关键路径上存在着效率低下的计算。这些问题可能与库所倡导的编码风格有关,也可能毫无瓜葛!它甚至可能是你团队内部更深层次工程文化问题的冰山一角。无论如何,若未对问题进行彻底的诊断就草率切换技术方案,其结果大概率是白费工夫。

有趣的是,在你深入排查现有代码问题的过程中,或许会豁然开朗:根本无需一个专门的状态管理库。在“远古Redux时代”,各种类型的状态常常被不加区分地混为一谈。而今,许多这类问题早已有了针对特定场景的、更为精良的解决方案。

因此,对于你的具体用例而言,最合适的方案很可能并非用一个新库全盘替换旧库,而是根据不同状态的特性,逐步用三四个不同的小型库来取代旧库的相应部分——到那时,所谓的“状态管理”本身,几乎不再是一个值得你耗费心神的大问题。

你也可能正准备启动一个全新的项目,没有历史包袱的束缚,期望从一开始就选定最理想的技术栈,其中自然包括状态管理方案。你希望避免项目上线一年后,所选的库因 очередная “技术圈宫斗”而被淘汰,迫使团队仓促迁移到一个完全陌生的体系。若你属于这种情况,我十分欣赏你的远见卓识——接下来的内容,正是为你量身打造的。

无需状态管理库的状态问题

那么,我们究竟在管理一种称之为“state”的东西,它到底是什么?从本质上讲,它不过是一些数据。这些数据能够影响一个系统的运作方式或外在行为。举个例子,当你在品尝冰淇淋时,你大脑这个“系统”的state可以是:

  • 正满怀期待

  • 正在享受美味

  • 品尝完毕,心满意足

或者,将焦点拉回到React的语境下,state可能涵盖:

  • 一个模态框的开启/关闭状态(open/closed)

  • 从某个API获取数据的进度(无数据 / 加载中 / 加载失败 / 加载成功)

  • 一个组件的生命周期状态(已挂载 / 未挂载)

  • 以及任何其他能够影响屏幕渲染内容或UI对用户交互响应模式的数据。

谈到数据与React……

Remote State(远程状态)

在所有“状态管理”的范畴中,有一个极其特殊且通常复杂程度最高的用例,那就是处理“远程”数据。这些数据存在于应用的外部,例如数据库中,我们通常需要通过(大多数情况下的)REST接口来获取,并将其整合进React应用。

即便是一个看似最基础的“获取并渲染”的场景,其背后的复杂性也远超想象。UI至少需要应对这三种状态:

  • 数据尚未就绪

  • 数据正在加载

  • 数据加载完毕

但随后,加载过程可能遭遇波折,比如服务器发生故障。因此,你必须加入错误处理逻辑。同时,若有两个或更多组件需要从同一接口拉取数据,你显然不希望它们各自发起重复的请求。对了,如果你在一个页面获取了这份数据,很可能也期望在应用的别处复用它,这就引出了缓存的需求。与此同时,你可能还需要一套机制来定期刷新缓存,防止数据陈旧,或在必要时强制清除缓存。

谈及缓存,你肯定不希望看到“请求瀑布流”的发生吧?比如,某个数据请求被置于一个条件渲染的组件内,只有在另一个毫不相关的请求完成后才能被触发。在这种情况下,你更希望能够并行发起这些请求,提前预取那些“隐藏”的数据并置入缓存,待到真正需要时再从缓存中读取。

顺便一提,我以上所讨论的,还仅仅是“获取、渲染、然后抛诸脑后”这类简单用例!可一旦你需要在用户交互后才去请求数据呢?那么你就必须处理竞态条件以及由此衍生的额外复杂性。如果这些数据还支持修改,你将面临更大的挑战。特别是当你期望引入“乐观更新”以提升用户体验,同时又要竭力维护数据的一致性时,情况会变得异常棘手。

所以,如果你正计划从一个基于Redux的老项目进行迁移,那么你Redux代码库中极有可能有80%的内容都在与上述这些问题作斗争。在这种情况下,你需要的并非一个状态管理库。你真正需要的,是一个为React量身打造的、优秀的数据管理库。它应当能优雅地解决上述所有问题,并具备以下品质:

  • 专为React生态设计

  • 得到持续的维护

  • 拥有良好的社区口碑

  • 文档详实完备

  • 稳定可靠——至少已发布了1.x以上的正式版本,并且不会每隔半年就进行一次颠覆性的重写。

在此类场景下,我默认的首选是 TanStack Query(其前身为React Query)。我已声明本文是观点文,而非“让我们共同探讨”的研讨会!但讲真的,如果你还未曾体验过从一个基于Redux的、陈旧的自定义数据获取方案迁移到TanStack Query,务必一试。其带来的开发体验提升,足以让你为之折服,你的开发日常将焕然一新,而那原本占据80%的Redux代码将随之烟消云散。

想在组件中获取数据,并同时处理好加载中和错误状态?易如反掌:

function Component() {
  const { isPending, error, data } = useQuery({
    queryKey: ['my-data'],
    queryFn: () => fetch('https://my-url/data').then((res) => res.json()),
  });

  if (isPending) return 'Loading...';
  if (error) return 'Oops, something went wrong';

  return ... // 根据 data 渲染内容
}

想在另一个组件中从同一接口获取数据,但又不想重复发请求?你完全无需为此操心——只要使用相同的 queryKey,这个库会自动为你打理好一切。

想预取并缓存某些请求?无需改动上述代码逻辑,只需在你希望触发预取的时机调用 queryClient.prefetchQuery,剩下的工作库会全权负责。

想实现分页查询?乐观更新?基于特定条件的重试策略?这些都无需你费心,此库均已内建支持。

我很少对某个工具表现出如此强烈的热情,但这个库确实是个例外。如果你因某些缘故不喜欢TanStack Query,它还有一个强劲的竞争者——SWR。这两个库同样出色、功能强大,提供的能力也大体相当。它们的API风格略有差异:TanStack Query由独立开发者维护,而SWR则出自Vercel之手。因此,最终的抉择更多取决于你对维护方的信任度,以及你个人更偏爱哪种API设计。不妨都尝试一下,凭直觉做出决定。

与此同时,我们来聊聊另一个常见的“远程”数据存储地——它同样可以承载与你React应用相关的信息。

URL state

网页的URL,实际上也能被视为一种状态载体,不是吗?当URL变更时,UI理应随之做出响应。在现代应用中,这种响应可以千变万化:比如导航至一个新页面,或是依据查询参数(query parameters)来切换当前激活的标签页。

如今,URL的核心部分(即pathname)几乎都由外部路由库掌控,并且其结构往往与目录和文件结构挂钩(例如在Next.js中)。因此,这部分内容通常不被划入状态管理的讨论范畴。

但查询字符串(query string)部分则截然不同。它常被用来存储一些更为精细的信息,这些信息直接影响当前页面的具体行为或展示细节。看看这个URL:/somepath?search="test"&tab=1&sidebar=open&onboarding=step1。问号之后的所有内容都是状态,它们定义了当前哪个标签页被激活、侧边栏是展开还是收起,以及新手引导流程进行到了哪一步。当URL变化时,UI应同步更新;反之,当用户在引导流程中切换步骤或点击新标签页时,URL也应随之改变。

在早期的Redux应用中,你经常能看到大量为了实现URL与UI双向同步而编写的手动逻辑。而如今,部分路由库已经能自动帮你处理这项工作。以React Router为例,它提供了 useSearchParams 这个Hook,让你可以像操作state一样来使用它:

export function SomeComponent() {
  const [searchParams, setSearchParams] = useSearchParams();
  // ...
}

然而,并非所有路由库都如此“体贴”。比如Next.js,虽然它提供了便捷的Hook来读取search params,但若你想将其与组件内部的state同步——尤其涉及到更新操作——你仍需自己编写不少迂回的代码。

如果你恰好面临这种窘境,我有一条能彻底革新你开发体验的建议:请放弃手动同步的执念。 手动维系本地state与URL之间的同步,是一条布满荆棘与诡异bug的崎岖之路。不要走这条路,去拥抱 nuqs 这个库吧。

正如TanStack Query颠覆了远程状态的管理范式,这个名字略显奇特但功能强大的库,将让你的查询参数管理体验焕然一新。

使用 nuqs 将新手引导(onboarding)状态同步到URL,代码大致如下:

export function MyApp() {
  const [step, setStep] = useQueryState('onboarding');

  return (
    <>
      <button onClick={() => setStep('step2')}>Next Step</button>
    </>
  );
}

如果你想为标签页设置一个默认值,比如当URL参数不存在时默认为 1,并且希望得到的是一个真正的数字而非字符串,完全没问题:

export function MyApp() {
  const [tab, setTab] = useQueryState('tab', parseAsInteger.withDefault(1));

  return (
    <>
      <button onClick={() => setTab(2)}>Second tab</button>
    </>
  );
}

如果你曾亲手实现过上述逻辑,看到这个示例时或许已经感慨万千了。

Local State(本地状态)

在后Redux时代,还存在另一类完全无需任何状态管理库的状态类型——即 本地状态 。譬如:

  • 下拉菜单是展开还是闭合?

  • 提示框(tooltip)是否可见?

  • 组件是否已成功挂载?

这些信息都局限于组件的逻辑边界之内,无需在组件间进行传递与共享。

// isOpen 是一个局部状态,无需共享
export function CreateIssueComponent() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <button onClick={() => setIsOpen(true)}>Open Create Issue Dialog</button>
      {isOpen && <CreateIssueDialog onClose={() => setIsOpen(false)} />}
    </>
  );
}

之所以在此提及本地状态,是因为许多遗留项目——特别是那些过度依赖Redux的应用——习惯性地将所有状态都纳入全局状态库进行统一管理。但如果你是从零开始构建一个新项目,对于这类纯粹的本地需求,完全没有理由引入任何额外的库。

当然,当你需要在多个组件之间共享这类状态时,事情就开始变得微妙起来了。

Shared State(共享状态)

我们来构思一个例子。假设你的应用中有一个可折叠的左侧面板,用户可以通过多种途径来控制它的展开与收起:

  • 点击面板右边缘的悬浮按钮。

  • 拖动面板边缘来调整其宽度。

  • 点击顶部导航栏中的“展开”或“收起”图标。

  • 使用快捷键进入应用的“全屏编辑模式”(这可能通过点击按钮或快捷键触发)。

换言之,来自应用不同角落的一系列组件——它们彼此之间可能毫无关联——却都希望能够访问并修改这个侧边栏的“私有”状态。

Props Drilling

共享此类信息的一种方式是运用所谓的“状态提升”(lifting state up)技术。你需要找到所有相关组件的最近公共祖先,将状态置于该处,然后通过props将状态值和更新函数逐层传递下去。结果可想而知,场面会相当混乱:

export function MyApp() {
  const [isSidebarOpen, setIsSidebarOpen] = useState(false);

  return (
    <>
      <TopBar 
        isSidebarOpen={isSidebarOpen} 
        setIsSidebarOpen={setIsSidebarOpen} 
      />
      <div className="content">
        <Sidebar 
          isOpen={isSidebarOpen} 
          setIsOpen={setIsSidebarOpen} 
        />
        <div className="main">
          <MainArea 
            isSidebarOpen={isSidebarOpen} 
            setIsSidebarOpen={setIsSidebarOpen} 
          />
        </div>
      </div>
      <KeyboardShortcutsController 
        isSidebarOpen={isSidebarOpen} 
        setIsSidebarOpen={setIsSidebarOpen} 
      />
    </>
  );
}

此刻,侧边栏的状态弥漫在应用的各个角落。整个代码库因为充斥着这些仅用于数据传递的props而变得晦涩难懂。而且,只要你试图重构这部分状态,几乎所有相关的组件代码都得随之修改。

更糟糕的是,在这种模式下,组件层级中的每一个节点都会随着状态的变更而重渲染——并且你对此束手无策。无论你施加多少次 memo 优化,都无济于事,因为每次状态更新都会导致相关props的引用改变,从而引发组件的重新渲染。这确实非常糟糕。

顺带一提,这种模式被称为“props drilling”(属性钻探)。当然,在父子组件间偶尔进行状态共享时,这种方式是合理且可行的。但如果你需要跨越三层以上的组件层级来传递状态,或者类似的情况在整个应用中反复出现,那么这很可能是一个信号:你的架构出问题了。

Context

当你的应用饱受props drilling之苦时,Context便能大显身手。Context是React提供的一种特殊机制,用于在组件间共享数据,它允许你“跨越”组件层级,无需通过props就能将数据传递给任意深度的子组件。

其核心思想如下:

  1. 你有一些需要在多个独立组件间共享的状态。

  2. 你将这部分状态逻辑抽离到一个独立的组件中。

  3. 在该组件内部创建一个Context,并将状态存入其中。

  4. 然后将这个组件渲染在应用的顶层或相关子树的根部。

  5. 之后,应用中任何位于该组件之下的子孙组件,都可以直接访问这个Context,从而获取或更新这份共享状态。

从代码层面审视,若我们用Context来重构之前的“sidebar”示例,首先需要创建一个带有默认值的Context:

const SidebarContext = React.createContext({
  isSidebarOpen: false,
  setIsSidebarOpen: (isOpen: boolean) => {},
});

接着,创建一个用于包裹应用的“Provider”组件,它负责提供Context的值:

const SidebarProvider = ({ children }) => {
  const [isSidebarOpen, setIsSidebarOpen] = React.useState(false);

  const value = React.useMemo(
    () => ({ isSidebarOpen, setIsSidebarOpen }),
    [isSidebarOpen],
  );

  // "value" 是注入到Context中的数据
  // 所有消费此Context的组件都能访问到它
  return (
    <SidebarContext.Provider value={value}>
      {children}
    </SidebarContext.Provider>
  );
};

在原本状态所在的位置,用这个Provider进行包裹:

// SidebarProvider 包裹整个应用
// 其内部的所有组件都能访问到Context的值
export function MyApp() {
  return (
    <SidebarProvider>
      <TopBar />
      <div className="content">
        <Sidebar />
        <div className="main">
          <MainArea />
        </div>
      </div>
      <KeyboardShortcutsController />
    </SidebarProvider>
  );
}

最后,在真正需要的地方直接消费Context的值,例如在 TopBar 组件内部的一个小按钮中切换sidebar的显示状态:

const SmallToggleSidebarButton = () => {
  const { isSidebarOpen, setIsSidebarOpen } = useSidebarContext();

  return (
    <button 
      onClick={() => setIsSidebarOpen(!isSidebarOpen)}
    >
      Toggle Sidebar
    </button>
  );
};

而且,由于“切换”功能非常通用,我们甚至可以将其封装成一个预定义的API,添加到SidebarContext中,供所有消费者直接调用:

const SidebarProvider = ({ children }) => {
  const [isSidebarOpen, setIsSidebarOpen] = React.useState(false);

  const value = React.useMemo(
    () => ({
      isSidebarOpen,
      setIsSidebarOpen,
      // 添加 "toggle" API
      toggleSidebar: () => setIsSidebarOpen((prev) => !prev),
    }),
    [isSidebarOpen],
  );

  return (
    <SidebarContext.Provider value={value}>
      {children}
    </SidebarContext.Provider>
  );
};

如此一来,在按钮组件中使用这个API就显得更加优雅了:

const SmallToggleSidebarButton = () => {
  const { toggleSidebar } = useSidebarContext();

  return (
    <button onClick={() => toggleSidebar()}>
      Toggle Sidebar
    </button>
  );
};

相较于props drilling,这种方式带来了显而易见的益处:

  • 代码更加清晰,可读性显著提升,不再有那些毫无意义的props层层传递。

  • 重构状态时,无需再改动整个组件树——只需聚焦于真正消费该状态的组件即可。

  • 如果你没有直接暴露状态,而是封装了如 toggleSidebar 这样合理的API,那么未来的重构可能仅限于Provider的内部实现,消费者代码无需任何改动。

  • 代码实现了高度内聚和职责分离,这始终是软件工程的良好实践。

在性能上,它甚至可能带来提升——尽管你可能听闻Context对性能“不友好”。但实际上,只有那些真正消费该Context的组件,才会在状态变化时触发重渲染。而我们从中间层级移除掉的那些“中转站”组件,反而不会再因不相关的状态变化而渲染。

然而,Context也绝非银弹。如果你问我是否推荐在应用中大规模使用Context,我的回答是:绝对不! 原因如下:

不要用Context来管理所有共享状态

如你所见,为了让Context正常工作,我们必须引入一个“Provider”组件。这个Provider至少要被放置在所有需要访问该Context的组件的最近公共祖先之上。

// 任何需要访问Sidebar状态的组件
// 都必须被渲染在SidebarProvider的内部
export function MyApp() {
  return (
    <SidebarProvider>
      ...
    </SidebarProvider>
  );
}

这是Context的基本用法,看似无懈可击,对吧?但问题恰恰由此开始……

如果我想共享另一种状态,比如应用的主题(Theming),很自然地会再引入另一个Provider:

export function MyApp() {
  return (
    <ThemingProvider>
      <SidebarProvider>
        ...
      </SidebarProvider>
    </ThemingProvider>
  );
}

看起来依然风平浪静,不是吗?但随着你想共享的状态越来越多,麻烦也接踵而至。当你又需要共享另一份状态时,结构就演变成了这样:

export function MyApp() {
  return (
    <SomethingElse>
      <ThemingProvider>
        <SidebarProvider>
          ...
        </SidebarProvider>
      </ThemingProvider>
    </SomethingElse>
  );
}

至此,你的组件树开始陷入层层嵌套的困境,这不仅降低了代码的可读性和可维护性,也让应用结构变得愈发脆弱。每次新增一个全局状态,你都得引入一个新的Provider,并小心翼翼地将其安插在正确的位置。发展到一定阶段,你可能会尝试对某些Provider进行分组,但其他人可能无法领会你的分组意图,又在组外添加了新的Provider。有些Provider开始相互依赖,有些则根本不适合置于应用根部,于是你试图将它们下移到更靠近消费方的地方——但在下一次重构中却忘得一干二净,最终导致某些依赖Context的组件行为异常,因为它们“丢失”了上层的Provider。

这就是臭名昭著的“Provider地狱”(Providers Hell)。这种Provider模式在你只需在整个应用中共享一两个状态时非常奏效。比如,你的代码中可能只有“主题”和“用户认证状态”需要全局共享。在这种情况下,引入两个Context Provider是完全合理的。但一旦共享状态的数量超过这个范畴,局面就会迅速失控。

在这种情况下,你可能会萌生一个念头:将所有这些共享状态整合到一个Provider中,并通过逻辑结构将它们区隔开。比如这样:

const SharedStateContext = React.createContext({
  sidebar: {
    isSidebarOpen: false,
    setIsSidebarOpen: (isOpen: boolean) => {},
    toggleSidebar: () => {},
  },
  theming: {
    isDarkMode: false,
    setIsDarkMode: (isDark: boolean) => {},
    toggleDarkMode: () => {},
  },
  user: {
    // 与用户认证相关的状态
  },
  // 其他共享状态
});

const useSharedStateContext = () => React.useContext(SharedStateContext);

const SharedStateProvider = ({ children }) => {
  // 在这里实现所有的state和逻辑
  return (
    <SharedStateContext.Provider value={value}>
      {children}
    </SharedStateContext.Provider>
  );
};

然后你只需要一个Provider就能覆盖整个应用:

export function MyApp() {
  return (
    {/* 唯一的 Provider */}
    <SharedStateProvider>
      {/* 应用的其余部分 */}
    </SharedStateProvider>
  );
}

在其他组件中,你就可以通过点号来访问所需的一切:

const SmallToggleSidebarButton = () => {
  // 只解构出sidebar相关的内容
  const { sidebar } = useSharedStateContext();

  return (
    <button onClick={() => sidebar.toggleSidebar()}>
      Toggle Sidebar
    </button>
  );
};

从技术上讲,此法可行。至于它是否遵循“关注点分离”的设计原则,尚有待商榷,但我们暂且搁置此议。真正的巨大隐患在于性能——更确切地说,是由Provider内部状态变化所触发的重渲染风暴。

你看,Context的一项关键局限在于:只要Context的值发生变化,所有消费这个Context的组件都会被强制重新渲染,无一幸免! 哪怕你只更新了其中一个微小的状态(比如 theming),那些只关心 sidebar 状态的组件也同样会被迫重渲染——即便它们所依赖的数据切片根本没有变化。

这会导致大量不必要的渲染,严重拖累性能,尤其是在大型应用中,问题会愈发突出。在上面的例子中,这意味着即使sidebar的状态保持不变,只要theming的状态一变,SmallToggleSidebarButton 也会重新渲染。反之亦然。对于像上面这样复杂且分布广泛的状态集合,每一次用户交互都可能引发整个应用的连锁重渲染。

如果应用规模尚小,这或许还能容忍。但你也可能遭遇侧边栏在每次交互时都卡顿数秒的窘境——用户绝对不会欣赏这种体验。当然,我们应避免过早优化,凡事应以性能测量为准。但可以肯定的是,一旦你的应用中共享状态的数量超过一两个,滥用Provider几乎必然会给你带来痛苦、bug和性能问题。

诚然,存在一些缓解措施,比如将庞大的Context拆分成更小的Provider。但说实话,到了这个地步,你其实已经在亲手“重造一个Zustand”了——那又何必不从一开始就直接选用Zustand呢?

这便自然而然地引出了我们讨论的终点——状态管理库(state management libraries)!

外部状态管理库

只有当你的应用中确实存在更为复杂的共享状态,并且你预见到Context已无法胜任时,才真正到了考虑引入外部状态管理库的时刻。

幸运的是,前文的铺垫已足够充分,我们现在对于该寻找何种方案,心中已有了清晰的蓝图。首先,通过选用一个数据管理库(如TanStack Query、SWR),我们已经消除了普通应用中约80%的状态管理难题。接着,通过使用 nuqs 来驾驭URL状态,又解决了大约10%。现在,摆在我们面前的,只剩下最后那10%的挑战了!

考虑到这一点,我在挑选共享状态解决方案时,首要看重的便是简洁性。毕竟,剩下的这10%已是精简后的核心,我不希望在此处再投入过多的心智负担。我需要一个配置极其简便、不引入全新抽象术语的方案。我期望通过阅读代码就能直观地理解其意图与行为,而无需频繁翻阅文档。

任何带有“你需要忘掉之前学的一切”暗示,或引入某种“全新的、概念化的思维模型”的工具,都会立即被我排除。这些宏大的理念若用于创造一门颠覆性的编程语言,或许尚可理解。但对于一个普通React应用中那为数不多的共享状态问题而言,实在是杀鸡用牛刀。

其次,我们始终可以利用Context在组件间共享数据。但其症结在于:Context不具备良好的可扩展性——它会带来“Provider地狱”和那些无法规避的冗余重渲染。这就意味着,一个合格的外部状态管理库必须能够解决这些痛点,否则其存在便毫无意义。它应满足以下几点:

  • 最好只有一个全局Provider,甚至完全不需要Provider;

  • 应允许我们仅订阅所需的状态切片;

  • 并且我们要能确信:只要该状态切片未发生变化,组件就不会被重新渲染。

此外,既然我们身处React的世界,这个库就应当遵循React的哲学与工作模式。也就是说,它应该:

  • 支持最新版本的React;

  • 能在SSR(服务端渲染)和RSC(React Server Components)场景下正常工作;

  • 基于Hooks;

  • 遵循单向数据流;

  • 采用声明式的编程模型。

顺带一提:任何在其描述中包含“signals”或“observables”字眼的库,都会被我直接淘汰。因为坦白说,它们很难通过我们前面提到的“简洁性”测试 😅。需要说明的是:我并非否定“signals”和“observables”这些模式本身的价值。只是它们确实要求开发者完成一次从典型React思维到新范式的重大思维转换。而且,这些模式本身并不直观,学习曲线相当陡峭。对于那些在接触React之前没有相关背景的开发者而言,这些概念往往会带来巨大的困惑和上手难度。

回到状态管理库本身。由于这些库大多是开源项目,我希望对其未来抱有一定信心——至少在接下来的几年内能够持续存在。这意味着它应具备以下特质之一:

  • 足够流行:这样即使项目遭遇变故,也很可能会有社区成员接手维护;

  • 或者,它由几个稳定的核心维护者或某个在开源社区享有良好声誉的公司进行维护。

上述这些标准只是略微提高了成功的概率,但并不能保证万无一失。这也是为何我格外强调“简洁性”和“与React理念的契合度”。因为一旦这个库出现问题,我希望自己能以最小的代价切换到另一个相似的解决方案,而无需重写半个项目。

现在,评判标准已经明晰,我们不妨来打个分,看看结果如何?😅

根据“State of React”调查,当前最受欢迎的状态管理库大致有以下这些:

我对它们的评估如下:

简洁性 (Simplicity)

  • 👎 Redux:绝对不行。Redux因其繁琐的样板代码和陡峭的学习曲线而备受诟病。Redux Toolkit的诞生就是为了“简化Redux”,这本身就说明了问题。

  • 😐 Redux Toolkit:或许也不行。表面上看起来尚可(虽然我已久未使用),但仍然涉及过多的概念需要学习。

  • 🎉 Zustand:这部分的绝对领跑者。你只需创建一些状态,然后通过一个Hook来使用它。看两行文档你就能上手,瞬间成为专家。

  • 👎 MobX:包含“signals”、“observables”这类概念,直接淘汰。

  • 👎 Jotai:引入了“atoms”等抽象概念,不行。

  • 👎 XState:“事件驱动”、“状态机”、“actors”、“模型”、“复杂逻辑”?这绝对不属于“简单”的范畴。

Provider数量 (One or fewer providers)

  • 🎉 从目前看,所有这些库要么仅需一个Provider,要么完全无需Provider。

状态未变则不重渲染 (No re-renders if the used state part doesn’t change)

  • 🎉 Redux / Redux Toolkit:通过创建selector可以实现。

  • 🎉 Zustand:开箱即用,天然支持。

  • 其余的库大概率也以某种形式支持此特性——毕竟若完全不支持,它们也难以流行。但无论如何,这个评判标准在最终选型时依然至关重要,特别是对于较新的库,务必通过实际代码验证它是否真正能做到按需更新。

与React理念及最新特性兼容性 (Compatible with React direction and latest features)

  • 要彻底验证这一点,需要投入大量时间用这些库进行实际编码。我只会在它们满足了前面所有其他标准,并且我认真考虑将其用于下一个项目时,才会进行如此深入的验证。

  • 🤨 Redux Toolkit:我确实需要再深入研究一下,才能做出最终判断。

  • 🎉 Zustand:从我的实践经验来看,它完美支持React的各项特性。

  • 🎉 Jotai:虽然我没用过,但它由Zustand的作者和维护者开发,理应也支持所有最新特性。

  • 👎 MobX:“signals”、“observables”——这些并非声明式范式,也不符合React的风格。不行。

  • 👎 XState:“事件驱动”模式,非声明式,与React风格相悖。依然不行。

开源活跃度 (Open source concerns)

  • 🎉 这些库看起来都在积极维护之中,没有明显的危险信号。这在情理之中,因为它们都是当前最受欢迎的库之一。

所以,结论是:Zustand 在所有维度的评估中都是赢家。 这也恰好与我在新项目中的默认技术栈选择相吻合:TanStack Query + nuqs + Zustand。

这是否意味着Zustand是“最好的”?绝对不是!😅 它只是完美契合了对我而言最重要的那套评估标准。换一套标准,结论可能截然不同。例如:

  • 如果我将“结构化、带有明确规范(opinionated)”作为首要考量,且不介意稍陡的学习曲线,那么 🎉 Redux Toolkit 将成为最终赢家。Zustand属于“自由发挥”型,而Redux则非常结构化、约束明确。在某些大型组织中,这种强制的一致性编码风格反而极具价值。

  • 如果我最看重的是“高级的调试体验”,🎉 Redux Toolkit 同样会胜出。其配套的Redux DevTools插件广受赞誉,调试体验异常强大。

  • 如果我极度推崇“状态机”模式,并且我的共享状态逻辑异常复杂(比如类似Figma那种交互级别),那我就会更深入地研究 🎉 XState。

因此,你懂的 😊。技术选型始终是基于实际需求、项目背景和个人偏好所做出的权衡。没有“最佳”,只有“最合适”。

总结

总结一下以上所有观点:

在绝大多数情况下,尤其当你并非立志打造下一个Figma时,你根本不需要一个所谓的“状态管理库”。那个将一切都塞进Redux的时代,确实已经一去不复返了。

将你的状态按照职责进行拆分,你会发现它们各自都有比任何“通用状态管理库”更优越的解决方案:

  • 远程状态 (Remote state)
    任何源自后端、API或数据库的数据,都应交由专业的数据请求库来打理。当前的主流选择是 TanStack Query 和 SWR。它们能帮你处理好缓存、请求去重、失效、重试、分页、乐观更新等一系列棘手问题,其效果几乎注定比你手写实现要好得多。

  • URL中的状态 (Query params)
    如果你的路由库没有提供便利的方式来同步URL查询参数与本地状态,就去使用 nuqs,别再徒劳地手动同步了——那将是一段充满痛苦的经历。

  • 本地状态 (Local state)
    实际上,海量的状态根本无需共享,我们之所以有此错觉,很大程度上是过去滥用Redux遗留下的思维定势。对于这类状态,直接使用React原生的 useState 或 useReducer 就足够了。

  • 共享状态 (Shared state)
    当你确实需要在多个松散耦合的组件之间共享状态时,可以先尝试 props drilling,如果props传递层级过深,再考虑使用 Context。只有当Context也显得力不从心时,才轮到真正的状态管理库登场。

遵循这套方法,你会发现大约90%的状态管理难题都会迎刃而解。剩下的那部分状态不仅数量更少,而且结构清晰、变化可控,从而更易于理解和维护。

至于哪个是“最佳”的状态管理库……其实根本不存在所谓的“最佳”。你应该先明确对你和你的项目而言最重要的评估标准,再依据这些标准去挑选最契合的库。

以我个人为例,我选择 Zustand,因为它极其简单、维护活跃,并且与React的开发哲学高度一致。但你完全可以做出截然不同的选择——这没有任何问题。

最后

送人玫瑰,手留余香,觉得有收获的朋友可以点赞,关注一波 ,我们组建了高级前端交流群,如果您热爱技术,想一起讨论技术,交流进步,不管是面试题,工作中的问题,难点热点都可以在交流群交流,为了拿到大Offer,邀请您进群,入群就送前端精选100本电子书以及 阿里面试前端精选资料 添加 下方小助手二维码或者扫描二维码 就可以进群。让我们一起学习进步.

图片

XSS漏洞之PDF生成:从XSS到服务端任意文件读取 XSS是最为常见的Web漏洞之一,多年来连续入选OWASP TOP10,相信大家都耳熟能详。 它是一种代码注入类的攻击,是一种客户端侧的攻击,攻击者通过在Web应用中注入恶意JavaScript代码,通过点击URL,最终在受害者浏览器端执行的一种漏洞。主要有反射型XSS、存储型XSS、基于DOM的XSS三类。XSS一些比较常规的危害大概有:重定向浏览器、窃取Cookie、浏览器劫持等。本文章侧重于发现XSS后的进一步利用。 主要介绍在某次实际测试过程中,发现XSS漏洞之后,如何进一步的利用,最终通过XSS达 阅读详情

相关推荐

Node-Red系列教程——NodeRed通过OPC UA读取数据并写入mysql

NodeRed通opcua读取西门子数据并存入mysql

鲸鱼姐的专栏 1万+

2025 React 状态管理终极指南!

2025 React 状态管理终极指南!

嗨,欢迎来到我的 优快云 博客小天地!一名深耕多年的技术发烧友。在这里,我将把日常工作中积累的宝贵经验,从复杂架构设计的精妙之处,到代码优化的实战技巧,毫无保留地分享给大家。 6157

VMware player桥接模式不能联网的解决方法

VMware虚拟机下主要使用两种网络连接方式:桥接模式、NAT模式。 桥接模式:查一下,虚拟机独立IP。 NAT模式:与电脑共享IP、需要映射应用服务的端口。 我的需求需要独立IP,于是使用桥接。 网络连接失败。 个人主机系统的网络设置: 设置 - 网络和 Internet - 更改适配器设置 给虚拟机设置网络适配器 只保留,点击确定,确定。 重新运行虚拟机。 ...

Mark_md的博客 9450

Redux Thunk与状态管理趋势:2025年展望

你还在为React应用中的异步数据流烦恼吗?状态更新混乱、组件逻辑臃肿、异步操作难以追踪?本文将深入解析Redux Thunk如何解决这些痛点,并探讨2025年状态管理的发展趋势。读完本文,你将掌握: - Redux Thunk的核心原理与使用方法 - 异步状态管理的最佳实践 - 2025年状态管理工具的演进方向 - 如何在实际项目中高效集成Redux Thunk ## Redux Thunk...

gitblog_01053的博客 381

使用扫频信号测量房间脉冲响应

脉冲响应的测量

liuderong0的博客 1765

QuickFix Java 讲解(一)概述、下载方法,和协议内容

本系列力求手把手教你怎样利用QuickFix Java 搭建自己的 FIX 协议收法平台,以及其中的注意事项。 所有源码的地址(免费): https://github.com/zongzhec/QuickFixPractise 1. 什么是FIX,QuickFix,Quick Java? 1.1. 什么是FIX 官网以及其他翻译自官网的帖子都太官方了,这里我们设想一个情景: 你是一个交易员,现在客户打电话来让你下个单买点股票。你啪啪啪的在你的机器上熟练地输入了下单指令。系统显示:成...

4574

现代前端状态管理:从原理到实战(Vue/React全栈方案)

现代前端状态管理核心摘要 状态管理是前端开发的核心挑战,本文系统梳理了2024年Vue/React生态下的状态管理最佳实践: 状态分类与管理原则 按作用域和更新特性分为4类状态(局部/全局、同步/异步) 遵循"最小作用域"原则,避免全局状态膨胀 三大核心原则:单一数据源、不可变性、可追溯变更 工具演进与选型 Vue生态推荐Pinia+TanStack Query组合 React生态推荐Zustand+TanStack Query方案 异步状态管理统一采用TanStack Query处理接

m0_74313397的博客 1202

Emotion-LLaMA实战指南:从零构建多模态情感识别系统(附Python代码)

本文提供了Emotion-LLaMA多模态情感识别系统的实战指南。通过详细的步骤,指导读者从零搭建开发环境、运行本地Demo、理解模型架构,并完成数据处理与模型训练。该创新模型融合视觉、听觉与文本信息,实现更精准、接近人类理解的情感分析与推理,并附有完整的Python代码实现。

weixin_29094775的博客 416

2024 年前端技术盘点与 2025 年技术展望

2024 年标志着前端向「编译时优化」和「服务端优先」范式转变,2025 年将迎来AI 增强开发工具链 Rust 化跨平台大一统三大趋势。深耕一个主流框架(React/Vue/Svelte)的深度优化能力掌握 Rust 基础以应对工具链变革学习 AI 辅助开发工作流设计。

qq_42264976的博客 1388

点到面点云配准(Point To Plane)算法知识详解和详细推导,C++代码实现

点到面 ICP (Iterative Closest Point) 是在 3D 点云配准中常见的一种变体,通过最小化点到对应面(由法向量定义的局部平面)的距离来提高收敛速度和精度。

qq_36812406的博客 1810

C#上位机通信层封装:西门子S7NetPlus库的优雅使用

支持S7-1200/1500(机架号0,槽号1)、S7-300/400(机架号/槽号需根据实际配置);支持位(Bit)、字节(Byte)、字(Word)、双字(DWord)、浮点数(Float/Double)等数据类型的读写;支持DB块、输入寄存器(I)、输出寄存器(Q)、内存寄存器(M)、定时器(T)、计数器(C)的操作;轻量无依赖,兼容.NET 5+。首先定义核心枚举和常量,统一规范参数类型,避免硬编码。/// 西门子PLC型号(对应不同的机架/槽号默认配置)

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1085

React Hooks 测试库终极指南:2025年发展趋势与未来展望

React Hooks 测试库是一个简单而完整的 React hooks 测试工具集,旨在鼓励良好的测试实践。作为 Testing Library 生态系统的重要组成部分,它专注于帮助开发者以用户实际使用组件的方式测试 React hooks,而不是测试实现细节。在 2025 年,随着 React 18 的普及和并发特性的广泛应用,React Hooks 测试库将继续保持其在 React 测试生态

gitblog_00270的博客 1068

MIKE21 MIKE软件 教程 0.1 软件介绍与教学目录

MIKE 21是一个专业的工程软件包,用于模拟河流、湖泊、河口、海湾、海岸及海洋的水流、波浪、泥沙及环境问题。在MIKE Zero集成平台中,主要有MIKE11,MIKE21,MIKE3三类软件,分别对应一维,二维,三维的水动力模型模拟。同时还包括MIKE HYDRO,MIKE FLOOD等其他功能,各软件的具体介绍请参考DHI公司的官方文档,在此不作赘述。学习过程中,对于任何操作界面的疑问,建议大家仔细阅读帮助文档(在有疑问的界面按F1调出),同时官方也提供了对应的线上和线下教学服务(免费+收费)。

Hello Word 2万+

现代前端开发框架对比:React、Vue 和 Svelte 的选择指南(2025年)

2025年,前端开发领域的技术迭代与AI工具的深度融合,使得开发者面临更复杂的框架选择挑战。React、Vue和Svelte作为当前主流的前端框架,凭借各自的核心理念和技术优势,持续引领行业风向。本文将从性能、开发体验、生态系统、适用场景及未来趋势等维度,深度解析三大框架的差异,并结合2025年的技术演进,为开发者提供科学的选择指南。

weixin_39444768的博客 4409

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

React 2025 完全指南:核心原理、实战技巧与性能优化

React 2025 完全指南:核心原理、实战技巧与性能优化

fruge365的博客 911

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

2025 年前端框架的深度解析与展望

在当今的互联网世界中,前端开发的重要性不言而喻,它直接关乎着用户与各类应用交互时的体验感受。而前端框架,就如同开发者们得力的助手一般,在开发过程中发挥着极为关键的作用。它能够显著提升开发效率,让代码的可维护性变得更强,同时还能拓展代码的功能范围,进而全方位提升应用的整体性能。

weixin_47592901的博客 1153

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

2025 年前端开发技术变革与展望

2025年前端开发趋势报告显示:主流框架持续创新,React凭借Server Components优化性能,Vue保持轻量灵活优势,Angular强化企业级支持,Svelte凭借高效编译崭露头角。构建工具Vite取代Webpack成为新宠,Tailwind CSS主导样式开发,Zustand替代Redux成为状态管理首选。前沿技术方面,SSR/SSG成为标配,微前端架构兴起,AI驱动开发重塑流程,MACH架构引领行业变革。开发者需掌握TypeScript、SSR/SSG和AI工具,关注跨平台与模块化开发,以

邮箱:uemgyth@163.com 2129

Python+React:2025年全栈开发黄金组合

随着技术的快速发展,2025年全栈开发的组合已经趋向于多样化。对于开发者来说,选择合适的技术栈至关重要,尤其是在构建复杂、高效且可扩展的应用时。在所有的选择中,Python与React已成为最受欢迎的全栈开发组合之一。本文将深入分析Python与React的优势、它们的协作机制以及如何利用这个组合构建高效的全栈应用。

weixin_42894922的博客 1048

奇舞周刊第547期:2025 年的 React + AI 技术栈

奇舞推荐■■■2025 年的 React + AI 技术栈本文介绍了2025年React与AI结合的技术栈,包括核心的React+TypeScript、Next.js作为元框架、Tailwind CSS+shadcn/ui用于样式、Zustand和TanStack Query分别用于客户端和服务器状态管理、Motion处理动画、Vitest等工具用于测试、Supabase作为数据库、React...

奇舞周刊 1606

Constate 2024路线图:React 19+无缝集成与未来功能展望

Constate 作为一款轻量级的 React 状态管理库,凭借其"React Context + State"的创新理念,让开发者能够轻松处理从局部状态到全局状态的各种场景。随着 React 19 的发布带来了诸多令人期待的新特性,Constate 团队也公布了一系列激动人心的更新计划,确保用户能够充分利用最新的 React 技术栈提升开发效率。 [![Constate 品牌标识](https

gitblog_00253的博客 859

2024年度前端技术总结:React、JavaScript、Material UI与Tailwind的实战心得

2024年是我在前端技术领域飞跃的一年。我通过学习React、JavaScript、Material UI和Tailwind等技术,不仅提升了自己的技术水平,还在多个项目中积累了宝贵的实践经验。展望2025年,我计划继续深入学习前端领域的其他技术,如TypeScript、Next.js等,进一步提升自己的技术栈,并在更多项目中应用所学的知识,提升项目的质量和效率。

lph159的博客 1032

ES2025新特性解析:Record与Tuple的不可变数据结构

不可变数据结构是现代编程中的重要概念,通过确保数据在创建后不被修改,可以显著提高代码的可预测性和安全性。其核心原理是通过结构共享和值比较来实现高效的内存使用和快速比较。在JavaScript生态中,不可变性对于状态管理、函数式编程和性能优化都具有重要价值。ES2025引入的原生Record和Tuple正是为了解决这些问题,它们使用`#{}`和`#[]`语法,提供了深度不可变的数据结构,特别适合React状态管理、Redux reducer和配置对象等场景。相比传统的Object.freeze或Immutab

hideto 537

2025年主流跨平台框架全面对比:选型指南与趋势展望

主流跨平台框架综合对比 本文对比了7种主流跨平台开发框架的特点与适用场景。Flutter在UI一致性和性能表现突出,适合中大型应用;React Native技术门槛低,适合前端团队快速开发;Kotlin Multiplatform专注逻辑复用,适合原生项目扩展;Unity是游戏开发首选;Tauri以轻量见长,适合桌面工具开发;.NET MAUI适合企业级项目;Electron生态成熟但资源占用高。各框架在开发语言、渲染方式、性能表现等方面差异显著,开发者需根据项目需求在性能、生态、开发效率等因素间权衡选择。

爱喝水程序员的博客 2192

18、状态库:中央魔法仓库——React 19 Zustand集成

—基于《魔法国会》第2025号协议,Zustand通过极简API、量子级渲染优化和凤凰社中间件协议,重构了React状态管理的能量传输规则。• 自动解除观测(unsubscribe on unmount)防止记忆泄漏。• 自动记忆封印(memoization)避免无意义能量波动(重渲染)• 凤凰社协议实现原子级更新(局部状态变更不触发全局熔毁)• 星链级状态同步(WebSocket+CRDT)• 支持多仓库量子纠缠(跨Store状态联动)• 组件仅订阅所需量子态(自动解除多余观测)

m0_60414444的博客 1098

Mantine vs 主流UI库:2025年前端技术选型终极指南

你还在为React UI库选型纠结?从性能优化到生态完整性,从开发体验到企业级支持,本文将通过多维度对比Mantine与Material-UI、Ant Design等主流框架,帮你解决90%的前端技术栈选择难题。读完本文你将获得: - 5大核心维度的量化对比表格 - 基于真实项目场景的选型决策流程图 - Mantine独家特性的实战应用案例 - 国内开发者专属的CDN配置方案 ## 技术选型的关...

gitblog_00403的博客 533

React 性能:memo / useMemo / useCallback

讲清 memo/useMemo/useCallback 的配合与边界,先测量再优化,避开常见过早优化。

JudithHuang的博客 327
上一篇: 技术、业务、管理:一个30岁前端的十字路口
下一篇: AI编程工具实力对决:2025年顶尖工具深度评测,从Cursor到v0,谁是你的最佳拍档?
React 中文社区
博客等级 码龄6年 119粉丝 41原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值