将React布局Context替换为Zustand状态仓库 #1590
将React布局Context替换为Zustand状态仓库 #1590
嘿,我正好之前做过类似的迁移,Zustand的简洁性真的能省不少事!下面我一步步给你讲怎么把原来的Context换成Zustand,包括你关心的useWindowSize和初始布局逻辑的放置位置。
首先,先确保你已经安装了Zustand:
npm install zustand # 或者用yarn yarn add zustand
接下来,我们创建一个单独的布局store文件(比如src/store/layoutStore.ts),把原来Context里的所有状态、逻辑都迁移过去:
import { create } from 'zustand'; import { useWindowSize } from '../hooks/useWindowSize'; // 替换成你实际的hook路径 // 先定义好你的断点常量(和原来保持一致) const Breakpoint = { MEDIUM: 768, LARGE: 1024, EXTRA_LARGE: 1280, }; export const useLayoutStore = create((set) => { // 1. 在这里使用useWindowSize,实时获取窗口尺寸 const windowSize = useWindowSize(); // 2. 根据窗口宽度计算各断点状态 const isMobile = windowSize.width <= Breakpoint.MEDIUM; const isTablet = windowSize.width > Breakpoint.MEDIUM && windowSize.width < Breakpoint.LARGE; const isLaptop = windowSize.width >= Breakpoint.LARGE && windowSize.width < Breakpoint.EXTRA_LARGE; const isDesktop = windowSize.width >= Breakpoint.EXTRA_LARGE; // 3. 初始布局逻辑:用useEffect执行一次初始化 useEffect(() => { const initialWidth = window.innerWidth; const isMobileDevice = initialWidth <= Breakpoint.MEDIUM; const isDesktopDevice = initialWidth >= Breakpoint.EXTRA_LARGE; if (isMobileDevice) { set({ showMobileNavigation: true }); } if (isDesktopDevice) { set({ menuIsOpen: true }); } }, []); // 4. 定义状态和更新函数 return { // 核心状态 menuIsOpen: false, overlayIsOpen: false, showMobileNavigation: false, // 断点状态(由windowSize实时计算) isMobile, isTablet, isLaptop, isDesktop, // 更新函数 setMenuIsOpen: (isOpen: boolean) => set({ menuIsOpen: isOpen }), setOverlayIsOpen: (isOpen: boolean) => set({ overlayIsOpen: isOpen }), setShowMobileNavigation: (show: boolean) => set({ showMobileNavigation: show }), }; });
关键部分解释:
useWindowSize的位置:直接放在store的创建函数里就好!因为Zustand允许在store内部使用React hooks,当窗口大小变化时,useWindowSize会触发store更新,对应的isMobile、isTablet等状态也会自动同步。- 初始布局的
useEffect:同样放在store内部,空依赖数组保证只在应用初始化时执行一次,完美替代原来Context里的初始逻辑。 - 无需Provider:Zustand不需要像Context那样用Provider包裹整个应用,你可以在任何组件里直接调用
useLayoutStore获取状态或更新函数。
在组件中使用的示例:
比如在导航组件里:
import { useLayoutStore } from '../store/layoutStore'; const Navigation = () => { // 只订阅需要的状态,提升性能 const isMobile = useLayoutStore(state => state.isMobile); const menuIsOpen = useLayoutStore(state => state.menuIsOpen); const setMenuIsOpen = useLayoutStore(state => state.setMenuIsOpen); return ( <nav> {isMobile ? ( <button onClick={() => setMenuIsOpen(!menuIsOpen)}> {menuIsOpen ? '关闭菜单' : '打开菜单'} </button> ) : ( <div className="desktop-menu">...</div> )} </nav> ); };
最后,你可以完全移除原来的LayoutContext和LayoutProvider了,Zustand已经帮你搞定全局状态管理!
备注:内容来源于stack exchange,提问作者Cytronic
相关产品推荐
相关产品推荐

