[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6EP05RRFF78F6Q2Z1G2K9YY":3,"skill-same:01M6EP05RRFF78F6Q2Z1G2K9YY":74},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":40,"linkOnly":41,"markdownContent":42,"markdownBody":43,"frontMatter":44,"refName":45,"commitSha":46,"skillDirectory":47,"forksCount":48,"repositoryHtmlUrl":49,"repositoryHomepageUrl":50,"ownerHtmlUrl":51,"ownerBlogUrl":6,"ownerDescription":52,"updatedAt":53,"install":54,"resources":67},"01M6EP05RRFF78F6Q2Z1G2K9YY","rn-zustand-patterns",null,"Zustand state management patterns for React Native. Use when working with Zustand stores, debugging state timing issues, or implementing async actions in Zustand.","ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",67,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fcjharmath\u002Frn-zustand-patterns\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39],"zustand","patterns","rn zustand patterns","react","debugging","state management","state","issues","actions","management","react native","use","async","zustand state","timing","native","2026-11-10 10:12:30",false,"---\nname: rn-zustand-patterns\ndescription: Zustand state management patterns for React Native. Use when working with Zustand stores, debugging state timing issues, or implementing async actions in Zustand.\n---\n\n# Zustand Patterns for React Native\n\n## Problem Statement\n\nZustand's simplicity hides important timing details. `set()` is synchronous, but React re-renders are batched. `getState()` escapes stale closures. Async actions in stores need careful handling. Understanding these internals prevents subtle bugs.\n\n---\n\n## Pattern: set() is Synchronous, Renders are Batched\n\n**Problem:** Assuming state is \"ready\" for React immediately after `set()`.\n\n```typescript\nconst useStore = create((set, get) => ({\n  count: 0,\n  \n  increment: () => {\n    set({ count: get().count + 1 });\n    \u002F\u002F State IS updated here (set is sync)\n    console.log(get().count); \u002F\u002F ✅ Shows new value\n    \n    \u002F\u002F But React hasn't re-rendered yet\n    \u002F\u002F Component will see old value until next render cycle\n  },\n}));\n```\n\n**Key insight:** \n- `set()` updates the store synchronously\n- `getState()` immediately reflects the new value\n- React components re-render asynchronously (batched)\n\n**When this matters:**\n- Chaining multiple state updates\n- Validating state after update\n- Debugging \"stale\" component values\n\n---\n\n## Pattern: getState() Escapes Stale Closures\n\n**Problem:** Callbacks and async functions capture state at creation time. Using `get()` or `getState()` always gets current state.\n\n```typescript\nconst useStore = create((set, get) => ({\n  answers: {},\n  \n  \u002F\u002F WRONG - state captured at function creation\n  saveAnswerBad: (questionId: string, value: number) => {\n    setTimeout(() => {\n      const answers = get().answers; \u002F\u002F ❌ This is fine\n      \u002F\u002F But if someone passed `answers` as a parameter...\n    }, 1000);\n  },\n  \n  \u002F\u002F CORRECT - always use get() for current state\n  saveAnswer: async (questionId: string, value: number) => {\n    await someAsyncOperation();\n    \u002F\u002F After await, use get() to ensure current state\n    const currentAnswers = get().answers;\n    set({ answers: { ...currentAnswers, [questionId]: value } });\n  },\n}));\n\n\u002F\u002F In components - same principle\nfunction Component() {\n  const answers = useStore((s) => s.answers);\n  \n  const handleSave = async () => {\n    await delay(1000);\n    \u002F\u002F answers here is stale! Captured at render time\n    \n    \u002F\u002F Use getState() for current value\n    const current = useStore.getState().answers;\n  };\n}\n```\n\n**Rule:** After any `await`, use `get()` or `getState()` - never rely on closure-captured values.\n\n---\n\n## Pattern: Async Actions in Stores\n\n**Problem:** Async actions need explicit `async\u002Fawait` and careful state reads after awaits.\n\n```typescript\nconst useStore = create((set, get) => ({\n  loading: false,\n  data: null,\n  error: null,\n  \n  \u002F\u002F WRONG - no async keyword, race condition prone\n  fetchDataBad: (id: string) => {\n    set({ loading: true });\n    api.fetch(id).then((data) => {\n      set({ data, loading: false });\n    });\n    \u002F\u002F Returns immediately, caller can't await\n  },\n  \n  \u002F\u002F CORRECT - proper async action\n  fetchData: async (id: string) => {\n    set({ loading: true, error: null });\n    \n    try {\n      const data = await api.fetch(id);\n      \u002F\u002F Re-read state after await if needed\n      if (get().loading) { \u002F\u002F Check we're still in loading state\n        set({ data, loading: false });\n      }\n    } catch (error) {\n      set({ error: error.message, loading: false });\n    }\n  },\n}));\n\n\u002F\u002F Caller can properly await\nawait useStore.getState().fetchData('123');\n```\n\n---\n\n## Pattern: Selector Stability\n\n**Problem:** Selectors that create new objects cause unnecessary re-renders.\n\n```typescript\n\u002F\u002F WRONG - creates new object every render\nconst data = useStore((state) => ({\n  name: state.name,\n  count: state.count,\n}));\n\n\u002F\u002F CORRECT - use multiple selectors\nconst name = useStore((state) => state.name);\nconst count = useStore((state) => state.count);\n\n\u002F\u002F OR - use shallow comparison (Zustand 4.x)\nimport { shallow } from 'zustand\u002Fshallow';\n\nconst { name, count } = useStore(\n  (state) => ({ name: state.name, count: state.count }),\n  shallow\n);\n\n\u002F\u002F Zustand 5.x - use useShallow hook\nimport { useShallow } from 'zustand\u002Freact\u002Fshallow';\n\nconst { name, count } = useStore(\n  useShallow((state) => ({ name: state.name, count: state.count }))\n);\n```\n\n---\n\n## Pattern: Derived State\n\n**Problem:** Computing derived values in selectors vs storing them.\n\n```typescript\nconst useStore = create((set, get) => ({\n  answers: {},\n  \n  \u002F\u002F WRONG - storing derived state that can become stale\n  totalAnswers: 0,\n  updateTotalAnswers: () => {\n    set({ totalAnswers: Object.keys(get().answers).length });\n  },\n  \n  \u002F\u002F CORRECT - compute in selector (always fresh)\n  \u002F\u002F answers: {},  \u002F\u002F Just store the source data\n}));\n\n\u002F\u002F Selector computes derived value\nconst totalAnswers = useStore((state) => Object.keys(state.answers).length);\n\n\u002F\u002F For expensive computations, memoize outside the store\nimport { useMemo } from 'react';\n\nfunction Component() {\n  const answers = useStore((state) => state.answers);\n  const expensiveResult = useMemo(() => {\n    return computeExpensiveAnalysis(answers);\n  }, [answers]);\n}\n```\n\n---\n\n## Pattern: Store Subscriptions for Side Effects\n\n**Problem:** Need to react to state changes outside React components.\n\n```typescript\n\u002F\u002F Subscribe to specific state changes\nconst unsubscribe = useStore.subscribe(\n  (state) => state.answers,\n  (answers, prevAnswers) => {\n    console.log('Answers changed:', { prev: prevAnswers, current: answers });\n    \u002F\u002F Persist to storage, send analytics, etc.\n  },\n  { equalityFn: shallow }\n);\n\n\u002F\u002F In Zustand 4.x with subscribeWithSelector middleware\nimport { subscribeWithSelector } from 'zustand\u002Fmiddleware';\n\nconst useStore = create(\n  subscribeWithSelector((set, get) => ({\n    answers: {},\n    \u002F\u002F ...\n  }))\n);\n```\n\n---\n\n## Pattern: Testing Zustand Stores\n\n**Problem:** Tests need to reset store state and verify async flows.\n\n```typescript\n\u002F\u002F Store with reset capability\nconst initialState = {\n  answers: {},\n  loading: false,\n};\n\nconst useStore = create((set, get) => ({\n  ...initialState,\n  \n  \u002F\u002F Actions...\n  \n  \u002F\u002F Reset for testing\n  _reset: () => set(initialState),\n}));\n\n\u002F\u002F Test\ndescribe('Assessment Store', () => {\n  beforeEach(() => {\n    useStore.getState()._reset();\n  });\n\n  it('saves answers during retake flow', async () => {\n    const store = useStore.getState();\n    \n    \u002F\u002F Full async flow\n    await store.loadCompletedAnswers(assessmentId);\n    await store.enableSkillAreaRetake('fundamentals');\n    \n    \u002F\u002F Verify state after async\n    expect(store.getState().retakeAreas).toContain('fundamentals');\n    \n    \u002F\u002F Continue flow\n    await store.saveAnswer('q1', 4);\n    \n    \u002F\u002F Verify final state\n    expect(useStore.getState().userAnswers['q1']).toBe(4);\n  });\n});\n```\n\n---\n\n## Pattern: Debugging State Changes\n\n**Problem:** Tracking down when\u002Fwhere state changed unexpectedly.\n\n```typescript\n\u002F\u002F Add logging middleware\nimport { devtools } from 'zustand\u002Fmiddleware';\n\nconst useStore = create(\n  devtools(\n    (set, get) => ({\n      \u002F\u002F ... your store\n    }),\n    { name: 'AssessmentStore' }\n  )\n);\n\n\u002F\u002F Manual logging for specific debugging\nconst useStore = create((set, get) => ({\n  answers: {},\n  \n  saveAnswer: (questionId: string, value: number) => {\n    console.log('[saveAnswer] Before:', {\n      questionId,\n      value,\n      currentAnswers: get().answers,\n      retakeAreas: get().retakeAreas,\n    });\n    \n    set((state) => ({\n      answers: { ...state.answers, [questionId]: value },\n    }));\n    \n    console.log('[saveAnswer] After:', {\n      answers: get().answers,\n    });\n  },\n}));\n```\n\n---\n\n## Common Pitfalls\n\n| Pitfall | Solution |\n|---------|----------|\n| Stale closure after await | Use `get()` after every await |\n| Selector returns new object | Use `shallow` or multiple selectors |\n| Action not awaitable | Add `async` keyword, return promise |\n| State seems stale in component | Component hasn't re-rendered yet - use `getState()` for immediate reads |\n| Can't find when state changed | Add devtools middleware or manual logging |\n\n---\n\n## Zustand 5.x Migration Notes\n\nIf upgrading from 4.x:\n\n```typescript\n\u002F\u002F 4.x - shallow from main package\nimport { shallow } from 'zustand\u002Fshallow';\n\n\u002F\u002F 5.x - useShallow hook for React\nimport { useShallow } from 'zustand\u002Freact\u002Fshallow';\n\n\u002F\u002F 4.x - type parameter often needed\nconst useStore = create\u003CStoreType>()((set, get) => ({...}));\n\n\u002F\u002F 5.x - improved type inference\nconst useStore = create((set, get) => ({...}));\n```\n","# Zustand Patterns for React Native\n\n## Problem Statement\n\nZustand's simplicity hides important timing details. `set()` is synchronous, but React re-renders are batched. `getState()` escapes stale closures. Async actions in stores need careful handling. Understanding these internals prevents subtle bugs.\n\n---\n\n## Pattern: set() is Synchronous, Renders are Batched\n\n**Problem:** Assuming state is \"ready\" for React immediately after `set()`.\n\n```typescript\nconst useStore = create((set, get) => ({\n  count: 0,\n  \n  increment: () => {\n    set({ count: get().count + 1 });\n    \u002F\u002F State IS updated here (set is sync)\n    console.log(get().count); \u002F\u002F ✅ Shows new value\n    \n    \u002F\u002F But React hasn't re-rendered yet\n    \u002F\u002F Component will see old value until next render cycle\n  },\n}));\n```\n\n**Key insight:** \n- `set()` updates the store synchronously\n- `getState()` immediately reflects the new value\n- React components re-render asynchronously (batched)\n\n**When this matters:**\n- Chaining multiple state updates\n- Validating state after update\n- Debugging \"stale\" component values\n\n---\n\n## Pattern: getState() Escapes Stale Closures\n\n**Problem:** Callbacks and async functions capture state at creation time. Using `get()` or `getState()` always gets current state.\n\n```typescript\nconst useStore = create((set, get) => ({\n  answers: {},\n  \n  \u002F\u002F WRONG - state captured at function creation\n  saveAnswerBad: (questionId: string, value: number) => {\n    setTimeout(() => {\n      const answers = get().answers; \u002F\u002F ❌ This is fine\n      \u002F\u002F But if someone passed `answers` as a parameter...\n    }, 1000);\n  },\n  \n  \u002F\u002F CORRECT - always use get() for current state\n  saveAnswer: async (questionId: string, value: number) => {\n    await someAsyncOperation();\n    \u002F\u002F After await, use get() to ensure current state\n    const currentAnswers = get().answers;\n    set({ answers: { ...currentAnswers, [questionId]: value } });\n  },\n}));\n\n\u002F\u002F In components - same principle\nfunction Component() {\n  const answers = useStore((s) => s.answers);\n  \n  const handleSave = async () => {\n    await delay(1000);\n    \u002F\u002F answers here is stale! Captured at render time\n    \n    \u002F\u002F Use getState() for current value\n    const current = useStore.getState().answers;\n  };\n}\n```\n\n**Rule:** After any `await`, use `get()` or `getState()` - never rely on closure-captured values.\n\n---\n\n## Pattern: Async Actions in Stores\n\n**Problem:** Async actions need explicit `async\u002Fawait` and careful state reads after awaits.\n\n```typescript\nconst useStore = create((set, get) => ({\n  loading: false,\n  data: null,\n  error: null,\n  \n  \u002F\u002F WRONG - no async keyword, race condition prone\n  fetchDataBad: (id: string) => {\n    set({ loading: true });\n    api.fetch(id).then((data) => {\n      set({ data, loading: false });\n    });\n    \u002F\u002F Returns immediately, caller can't await\n  },\n  \n  \u002F\u002F CORRECT - proper async action\n  fetchData: async (id: string) => {\n    set({ loading: true, error: null });\n    \n    try {\n      const data = await api.fetch(id);\n      \u002F\u002F Re-read state after await if needed\n      if (get().loading) { \u002F\u002F Check we're still in loading state\n        set({ data, loading: false });\n      }\n    } catch (error) {\n      set({ error: error.message, loading: false });\n    }\n  },\n}));\n\n\u002F\u002F Caller can properly await\nawait useStore.getState().fetchData('123');\n```\n\n---\n\n## Pattern: Selector Stability\n\n**Problem:** Selectors that create new objects cause unnecessary re-renders.\n\n```typescript\n\u002F\u002F WRONG - creates new object every render\nconst data = useStore((state) => ({\n  name: state.name,\n  count: state.count,\n}));\n\n\u002F\u002F CORRECT - use multiple selectors\nconst name = useStore((state) => state.name);\nconst count = useStore((state) => state.count);\n\n\u002F\u002F OR - use shallow comparison (Zustand 4.x)\nimport { shallow } from 'zustand\u002Fshallow';\n\nconst { name, count } = useStore(\n  (state) => ({ name: state.name, count: state.count }),\n  shallow\n);\n\n\u002F\u002F Zustand 5.x - use useShallow hook\nimport { useShallow } from 'zustand\u002Freact\u002Fshallow';\n\nconst { name, count } = useStore(\n  useShallow((state) => ({ name: state.name, count: state.count }))\n);\n```\n\n---\n\n## Pattern: Derived State\n\n**Problem:** Computing derived values in selectors vs storing them.\n\n```typescript\nconst useStore = create((set, get) => ({\n  answers: {},\n  \n  \u002F\u002F WRONG - storing derived state that can become stale\n  totalAnswers: 0,\n  updateTotalAnswers: () => {\n    set({ totalAnswers: Object.keys(get().answers).length });\n  },\n  \n  \u002F\u002F CORRECT - compute in selector (always fresh)\n  \u002F\u002F answers: {},  \u002F\u002F Just store the source data\n}));\n\n\u002F\u002F Selector computes derived value\nconst totalAnswers = useStore((state) => Object.keys(state.answers).length);\n\n\u002F\u002F For expensive computations, memoize outside the store\nimport { useMemo } from 'react';\n\nfunction Component() {\n  const answers = useStore((state) => state.answers);\n  const expensiveResult = useMemo(() => {\n    return computeExpensiveAnalysis(answers);\n  }, [answers]);\n}\n```\n\n---\n\n## Pattern: Store Subscriptions for Side Effects\n\n**Problem:** Need to react to state changes outside React components.\n\n```typescript\n\u002F\u002F Subscribe to specific state changes\nconst unsubscribe = useStore.subscribe(\n  (state) => state.answers,\n  (answers, prevAnswers) => {\n    console.log('Answers changed:', { prev: prevAnswers, current: answers });\n    \u002F\u002F Persist to storage, send analytics, etc.\n  },\n  { equalityFn: shallow }\n);\n\n\u002F\u002F In Zustand 4.x with subscribeWithSelector middleware\nimport { subscribeWithSelector } from 'zustand\u002Fmiddleware';\n\nconst useStore = create(\n  subscribeWithSelector((set, get) => ({\n    answers: {},\n    \u002F\u002F ...\n  }))\n);\n```\n\n---\n\n## Pattern: Testing Zustand Stores\n\n**Problem:** Tests need to reset store state and verify async flows.\n\n```typescript\n\u002F\u002F Store with reset capability\nconst initialState = {\n  answers: {},\n  loading: false,\n};\n\nconst useStore = create((set, get) => ({\n  ...initialState,\n  \n  \u002F\u002F Actions...\n  \n  \u002F\u002F Reset for testing\n  _reset: () => set(initialState),\n}));\n\n\u002F\u002F Test\ndescribe('Assessment Store', () => {\n  beforeEach(() => {\n    useStore.getState()._reset();\n  });\n\n  it('saves answers during retake flow', async () => {\n    const store = useStore.getState();\n    \n    \u002F\u002F Full async flow\n    await store.loadCompletedAnswers(assessmentId);\n    await store.enableSkillAreaRetake('fundamentals');\n    \n    \u002F\u002F Verify state after async\n    expect(store.getState().retakeAreas).toContain('fundamentals');\n    \n    \u002F\u002F Continue flow\n    await store.saveAnswer('q1', 4);\n    \n    \u002F\u002F Verify final state\n    expect(useStore.getState().userAnswers['q1']).toBe(4);\n  });\n});\n```\n\n---\n\n## Pattern: Debugging State Changes\n\n**Problem:** Tracking down when\u002Fwhere state changed unexpectedly.\n\n```typescript\n\u002F\u002F Add logging middleware\nimport { devtools } from 'zustand\u002Fmiddleware';\n\nconst useStore = create(\n  devtools(\n    (set, get) => ({\n      \u002F\u002F ... your store\n    }),\n    { name: 'AssessmentStore' }\n  )\n);\n\n\u002F\u002F Manual logging for specific debugging\nconst useStore = create((set, get) => ({\n  answers: {},\n  \n  saveAnswer: (questionId: string, value: number) => {\n    console.log('[saveAnswer] Before:', {\n      questionId,\n      value,\n      currentAnswers: get().answers,\n      retakeAreas: get().retakeAreas,\n    });\n    \n    set((state) => ({\n      answers: { ...state.answers, [questionId]: value },\n    }));\n    \n    console.log('[saveAnswer] After:', {\n      answers: get().answers,\n    });\n  },\n}));\n```\n\n---\n\n## Common Pitfalls\n\n| Pitfall | Solution |\n|---------|----------|\n| Stale closure after await | Use `get()` after every await |\n| Selector returns new object | Use `shallow` or multiple selectors |\n| Action not awaitable | Add `async` keyword, return promise |\n| State seems stale in component | Component hasn't re-rendered yet - use `getState()` for immediate reads |\n| Can't find when state changed | Add devtools middleware or manual logging |\n\n---\n\n## Zustand 5.x Migration Notes\n\nIf upgrading from 4.x:\n\n```typescript\n\u002F\u002F 4.x - shallow from main package\nimport { shallow } from 'zustand\u002Fshallow';\n\n\u002F\u002F 5.x - useShallow hook for React\nimport { useShallow } from 'zustand\u002Freact\u002Fshallow';\n\n\u002F\u002F 4.x - type parameter often needed\nconst useStore = create\u003CStoreType>()((set, get) => ({...}));\n\n\u002F\u002F 5.x - improved type inference\nconst useStore = create((set, get) => ({...}));\n```\n",{"name":5,"description":7},"main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002Faiskillstore\u002Fmarketplace\u002Fcjharmath\u002Frn-zustand-patterns",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":8,"skillName":5,"commands":55,"prompt":65,"zipAvailable":66},[56,59,62],{"tool":57,"command":58},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill rn-zustand-patterns",{"tool":60,"command":61},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill rn-zustand-patterns",{"tool":63,"command":64},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill rn-zustand-patterns","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fcjharmath\u002Frn-zustand-patterns\u002FSKILL.md",true,[68],{"path":69,"resourceType":70,"resourceTypeDesc":71,"sizeBytes":72,"sourceHtmlUrl":73},"skill-report.json","REFERENCE","参考文档",13072,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fcjharmath\u002Frn-zustand-patterns\u002Fskill-report.json",[75,87,97,106,112,119],{"skillNo":76,"name":77,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":78,"categories":79,"keywords":83,"publishedAt":40},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[80],{"categoryNo":81,"categoryName":82,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[84,85,86],"model","model hierarchy","model hierarchy skill",{"skillNo":88,"name":89,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":90,"categories":91,"keywords":93,"publishedAt":40},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[92],{"categoryNo":81,"categoryName":82,"taxonomyType":21,"taxonomyTypeDesc":22},[94,95,96],"MCP","zoom","zoom mcp",{"skillNo":98,"name":99,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":100,"categories":101,"keywords":102,"publishedAt":40},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[103,104,105,95],"sdk","zoom apps sdk","apps",{"skillNo":107,"name":108,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":109,"categories":110,"keywords":111,"publishedAt":40},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[108],{"skillNo":113,"name":114,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":115,"categories":116,"keywords":118,"publishedAt":40},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[117],{"categoryNo":81,"categoryName":82,"taxonomyType":21,"taxonomyTypeDesc":22},[114],{"skillNo":120,"name":121,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":122,"categories":123,"keywords":124,"publishedAt":40},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[121]]