@vetala/vetala 0.1.0-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @vetala/vetala might be problematic. Click here for more details.
- package/CONTRIBUTING.md +77 -0
- package/LICENSE +184 -0
- package/README.md +136 -0
- package/THIRD_PARTY_LICENSES.md +17 -0
- package/dist/src/agent.d.ts +30 -0
- package/dist/src/agent.js +216 -0
- package/dist/src/agent.js.map +1 -0
- package/dist/src/approvals.d.ts +18 -0
- package/dist/src/approvals.js +81 -0
- package/dist/src/approvals.js.map +1 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +87 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/config.d.ts +12 -0
- package/dist/src/config.js +183 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/context-memory.d.ts +7 -0
- package/dist/src/context-memory.js +96 -0
- package/dist/src/context-memory.js.map +1 -0
- package/dist/src/ink/command-suggestions.d.ts +7 -0
- package/dist/src/ink/command-suggestions.js +179 -0
- package/dist/src/ink/command-suggestions.js.map +1 -0
- package/dist/src/ink/ink-terminal-ui.d.ts +36 -0
- package/dist/src/ink/ink-terminal-ui.js +79 -0
- package/dist/src/ink/ink-terminal-ui.js.map +1 -0
- package/dist/src/ink/repl-app.d.ts +9 -0
- package/dist/src/ink/repl-app.js +789 -0
- package/dist/src/ink/repl-app.js.map +1 -0
- package/dist/src/ink/transcript-cards.d.ts +6 -0
- package/dist/src/ink/transcript-cards.js +24 -0
- package/dist/src/ink/transcript-cards.js.map +1 -0
- package/dist/src/path-policy.d.ts +11 -0
- package/dist/src/path-policy.js +67 -0
- package/dist/src/path-policy.js.map +1 -0
- package/dist/src/process-utils.d.ts +13 -0
- package/dist/src/process-utils.js +52 -0
- package/dist/src/process-utils.js.map +1 -0
- package/dist/src/repl.d.ts +9 -0
- package/dist/src/repl.js +13 -0
- package/dist/src/repl.js.map +1 -0
- package/dist/src/sarvam/client.d.ts +15 -0
- package/dist/src/sarvam/client.js +208 -0
- package/dist/src/sarvam/client.js.map +1 -0
- package/dist/src/sarvam/models.d.ts +2 -0
- package/dist/src/sarvam/models.js +7 -0
- package/dist/src/sarvam/models.js.map +1 -0
- package/dist/src/search-provider.d.ts +6 -0
- package/dist/src/search-provider.js +8 -0
- package/dist/src/search-provider.js.map +1 -0
- package/dist/src/session-store.d.ts +19 -0
- package/dist/src/session-store.js +318 -0
- package/dist/src/session-store.js.map +1 -0
- package/dist/src/skills/runtime.d.ts +26 -0
- package/dist/src/skills/runtime.js +317 -0
- package/dist/src/skills/runtime.js.map +1 -0
- package/dist/src/skills/types.d.ts +25 -0
- package/dist/src/skills/types.js +2 -0
- package/dist/src/skills/types.js.map +1 -0
- package/dist/src/terminal-ui.d.ts +29 -0
- package/dist/src/terminal-ui.js +236 -0
- package/dist/src/terminal-ui.js.map +1 -0
- package/dist/src/tools/filesystem.d.ts +2 -0
- package/dist/src/tools/filesystem.js +622 -0
- package/dist/src/tools/filesystem.js.map +1 -0
- package/dist/src/tools/git.d.ts +2 -0
- package/dist/src/tools/git.js +326 -0
- package/dist/src/tools/git.js.map +1 -0
- package/dist/src/tools/index.d.ts +6 -0
- package/dist/src/tools/index.js +21 -0
- package/dist/src/tools/index.js.map +1 -0
- package/dist/src/tools/registry.d.ts +15 -0
- package/dist/src/tools/registry.js +59 -0
- package/dist/src/tools/registry.js.map +1 -0
- package/dist/src/tools/shell.d.ts +2 -0
- package/dist/src/tools/shell.js +97 -0
- package/dist/src/tools/shell.js.map +1 -0
- package/dist/src/tools/skill.d.ts +3 -0
- package/dist/src/tools/skill.js +130 -0
- package/dist/src/tools/skill.js.map +1 -0
- package/dist/src/tools/web.d.ts +3 -0
- package/dist/src/tools/web.js +144 -0
- package/dist/src/tools/web.js.map +1 -0
- package/dist/src/types.d.ts +236 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/workspace-trust.d.ts +3 -0
- package/dist/src/workspace-trust.js +31 -0
- package/dist/src/workspace-trust.js.map +1 -0
- package/dist/src/xdg.d.ts +9 -0
- package/dist/src/xdg.js +77 -0
- package/dist/src/xdg.js.map +1 -0
- package/package.json +57 -0
- package/skill/agents-md-generator/SKILL.md +75 -0
- package/skill/agents-md-generator/references/agents_md_template.md +160 -0
- package/skill/agents-md-generator/references/loc_measurement.md +67 -0
- package/skill/agents-md-generator/references/monorepo_detection.md +78 -0
- package/skill/agents-md-generator/references/monorepo_strategy.md +60 -0
- package/skill/agents-md-generator/references/read_only_commands.md +151 -0
- package/skill/agents-md-generator/references/update_strategy.md +160 -0
- package/skill/agents-md-generator/references/working_agreements.md +53 -0
- package/skill/biz-opportunity-scout/SKILL.md +53 -0
- package/skill/biz-opportunity-scout/references/competitive_analysis.md +84 -0
- package/skill/biz-opportunity-scout/references/market_sizing.md +68 -0
- package/skill/biz-opportunity-scout/references/pmf_indicators.md +94 -0
- package/skill/biz-opportunity-scout/references/report_template.md +243 -0
- package/skill/biz-opportunity-scout/references/unit_economics.md +97 -0
- package/skill/code-review/SKILL.md +86 -0
- package/skill/code-review/references/change_analysis.md +116 -0
- package/skill/code-review/references/git_operations.md +115 -0
- package/skill/code-review/references/impact_detection.md +149 -0
- package/skill/code-review/references/output_format.md +137 -0
- package/skill/code-review/references/severity_criteria.md +100 -0
- package/skill/code-security-audit/SKILL.md +123 -0
- package/skill/code-security-audit/references/audit_process.md +277 -0
- package/skill/code-security-audit/references/remediation_patterns.md +599 -0
- package/skill/code-security-audit/references/report_format.md +391 -0
- package/skill/code-security-audit/references/security_domains.md +830 -0
- package/skill/code-security-audit/references/vulnerability_patterns.md +813 -0
- package/skill/composition-patterns/SKILL.md +83 -0
- package/skill/composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
- package/skill/composition-patterns/rules/architecture-compound-components.md +112 -0
- package/skill/composition-patterns/rules/patterns-children-over-render-props.md +87 -0
- package/skill/composition-patterns/rules/patterns-explicit-variants.md +100 -0
- package/skill/composition-patterns/rules/react19-no-forwardref.md +42 -0
- package/skill/composition-patterns/rules/state-context-interface.md +191 -0
- package/skill/composition-patterns/rules/state-decouple-implementation.md +113 -0
- package/skill/composition-patterns/rules/state-lift-state.md +125 -0
- package/skill/deploy-to-vercel/SKILL.md +293 -0
- package/skill/deploy-to-vercel/resources/deploy-sandbox.sh +301 -0
- package/skill/deploy-to-vercel/resources/deploy.sh +301 -0
- package/skill/doc/SKILL_GUIDELINES.md +138 -0
- package/skill/git-workflow/SKILL.md +94 -0
- package/skill/git-workflow/references/advanced-git.md +632 -0
- package/skill/git-workflow/references/branching-strategies.md +344 -0
- package/skill/git-workflow/references/ci-cd-integration.md +683 -0
- package/skill/git-workflow/references/code-quality-tools.md +351 -0
- package/skill/git-workflow/references/commit-conventions.md +439 -0
- package/skill/git-workflow/references/github-releases.md +288 -0
- package/skill/git-workflow/references/pull-request-workflow.md +773 -0
- package/skill/git-workflow/scripts/verify-git-workflow.sh +263 -0
- package/skill/jetbrains-vmoptions/SKILL.md +51 -0
- package/skill/jetbrains-vmoptions/references/common-options.md +357 -0
- package/skill/jetbrains-vmoptions/references/gc-options.md +350 -0
- package/skill/jetbrains-vmoptions/references/memory-options.md +339 -0
- package/skill/jetbrains-vmoptions/references/prerequisite-check.md +65 -0
- package/skill/kysely-converter/SKILL.md +62 -0
- package/skill/kysely-converter/references/delete.md +323 -0
- package/skill/kysely-converter/references/insert.md +386 -0
- package/skill/kysely-converter/references/operators.md +331 -0
- package/skill/kysely-converter/references/select.md +1000 -0
- package/skill/kysely-converter/references/update.md +349 -0
- package/skill/kysely-converter/references/window_function.md +537 -0
- package/skill/react-best-practices/SKILL.md +131 -0
- package/skill/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/skill/react-best-practices/rules/advanced-init-once.md +42 -0
- package/skill/react-best-practices/rules/advanced-use-latest.md +39 -0
- package/skill/react-best-practices/rules/async-api-routes.md +38 -0
- package/skill/react-best-practices/rules/async-defer-await.md +80 -0
- package/skill/react-best-practices/rules/async-dependencies.md +51 -0
- package/skill/react-best-practices/rules/async-parallel.md +28 -0
- package/skill/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/skill/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/skill/react-best-practices/rules/bundle-conditional.md +31 -0
- package/skill/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/skill/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/skill/react-best-practices/rules/bundle-preload.md +50 -0
- package/skill/react-best-practices/rules/client-event-listeners.md +74 -0
- package/skill/react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/skill/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/skill/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/skill/react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/skill/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/skill/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/skill/react-best-practices/rules/js-cache-storage.md +70 -0
- package/skill/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/skill/react-best-practices/rules/js-early-exit.md +50 -0
- package/skill/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/skill/react-best-practices/rules/js-index-maps.md +37 -0
- package/skill/react-best-practices/rules/js-length-check-first.md +49 -0
- package/skill/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/skill/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/skill/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/skill/react-best-practices/rules/rendering-activity.md +26 -0
- package/skill/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/skill/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/skill/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/skill/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/skill/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/skill/react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/skill/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/skill/react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/skill/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/skill/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/skill/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/skill/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/skill/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/skill/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/skill/react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/skill/react-best-practices/rules/rerender-memo.md +44 -0
- package/skill/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/skill/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/skill/react-best-practices/rules/rerender-transitions.md +40 -0
- package/skill/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/skill/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/skill/react-best-practices/rules/server-auth-actions.md +96 -0
- package/skill/react-best-practices/rules/server-cache-lru.md +41 -0
- package/skill/react-best-practices/rules/server-cache-react.md +76 -0
- package/skill/react-best-practices/rules/server-dedup-props.md +65 -0
- package/skill/react-best-practices/rules/server-hoist-static-io.md +142 -0
- package/skill/react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/skill/react-best-practices/rules/server-serialization.md +38 -0
- package/skill/react-native-skills/SKILL.md +115 -0
- package/skill/react-native-skills/rules/animation-derived-value.md +53 -0
- package/skill/react-native-skills/rules/animation-gesture-detector-press.md +95 -0
- package/skill/react-native-skills/rules/animation-gpu-properties.md +65 -0
- package/skill/react-native-skills/rules/design-system-compound-components.md +66 -0
- package/skill/react-native-skills/rules/fonts-config-plugin.md +71 -0
- package/skill/react-native-skills/rules/imports-design-system-folder.md +68 -0
- package/skill/react-native-skills/rules/js-hoist-intl.md +61 -0
- package/skill/react-native-skills/rules/list-performance-callbacks.md +44 -0
- package/skill/react-native-skills/rules/list-performance-function-references.md +132 -0
- package/skill/react-native-skills/rules/list-performance-images.md +53 -0
- package/skill/react-native-skills/rules/list-performance-inline-objects.md +97 -0
- package/skill/react-native-skills/rules/list-performance-item-expensive.md +94 -0
- package/skill/react-native-skills/rules/list-performance-item-memo.md +82 -0
- package/skill/react-native-skills/rules/list-performance-item-types.md +104 -0
- package/skill/react-native-skills/rules/list-performance-virtualize.md +67 -0
- package/skill/react-native-skills/rules/monorepo-native-deps-in-app.md +46 -0
- package/skill/react-native-skills/rules/monorepo-single-dependency-versions.md +63 -0
- package/skill/react-native-skills/rules/navigation-native-navigators.md +188 -0
- package/skill/react-native-skills/rules/react-compiler-destructure-functions.md +50 -0
- package/skill/react-native-skills/rules/react-compiler-reanimated-shared-values.md +48 -0
- package/skill/react-native-skills/rules/react-state-dispatcher.md +91 -0
- package/skill/react-native-skills/rules/react-state-fallback.md +56 -0
- package/skill/react-native-skills/rules/react-state-minimize.md +65 -0
- package/skill/react-native-skills/rules/rendering-no-falsy-and.md +74 -0
- package/skill/react-native-skills/rules/rendering-text-in-text-component.md +36 -0
- package/skill/react-native-skills/rules/scroll-position-no-state.md +82 -0
- package/skill/react-native-skills/rules/state-ground-truth.md +80 -0
- package/skill/react-native-skills/rules/ui-expo-image.md +66 -0
- package/skill/react-native-skills/rules/ui-image-gallery.md +104 -0
- package/skill/react-native-skills/rules/ui-measure-views.md +78 -0
- package/skill/react-native-skills/rules/ui-menus.md +174 -0
- package/skill/react-native-skills/rules/ui-native-modals.md +77 -0
- package/skill/react-native-skills/rules/ui-pressable.md +61 -0
- package/skill/react-native-skills/rules/ui-safe-area-scroll.md +65 -0
- package/skill/react-native-skills/rules/ui-scrollview-content-inset.md +45 -0
- package/skill/react-native-skills/rules/ui-styling.md +87 -0
- package/skill/react-vite-guide/SKILL.md +101 -0
- package/skill/react-vite-guide/references/composition-patterns.md +709 -0
- package/skill/react-vite-guide/references/performance-optimization.md +1222 -0
- package/skill/react-vite-guide/references/vite-specific.md +385 -0
- package/skill/react-vite-guide/references/web-interface.md +146 -0
- package/skill/skill-maker/SKILL.md +52 -0
- package/skill/skill-maker/references/content_spec.md +67 -0
- package/skill/skill-maker/references/frontmatter_spec.md +96 -0
- package/skill/skill-maker/references/input_validation.md +90 -0
- package/skill/skill-maker/references/skill_structure.md +74 -0
- package/skill/system-prompt-creator/SKILL.md +50 -0
- package/skill/system-prompt-creator/references/data_format_selection.md +135 -0
- package/skill/system-prompt-creator/references/multi_prompt_architecture.md +386 -0
- package/skill/system-prompt-creator/references/prompt_structure.md +140 -0
- package/skill/system-prompt-creator/references/quality_criteria.md +83 -0
- package/skill/typst-creator/SKILL.md +51 -0
- package/skill/typst-creator/references/layout.md +401 -0
- package/skill/typst-creator/references/math.md +297 -0
- package/skill/typst-creator/references/scripting.md +237 -0
- package/skill/typst-creator/references/styling.md +217 -0
- package/skill/typst-creator/references/syntax.md +234 -0
- package/skill/web-design-guidelines/SKILL.md +35 -0
- package/terminal.png +0 -0
|
@@ -0,0 +1,709 @@
|
|
|
1
|
+
# React Composition Patterns
|
|
2
|
+
|
|
3
|
+
Composition patterns for flexible, maintainable React 19 components. Covers compound components, state lifting, and internal composition as alternatives to boolean prop proliferation.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Component Architecture
|
|
8
|
+
|
|
9
|
+
**Impact: HIGH**
|
|
10
|
+
|
|
11
|
+
### 1.1 Avoid Boolean Prop Proliferation
|
|
12
|
+
|
|
13
|
+
**Impact: CRITICAL**
|
|
14
|
+
|
|
15
|
+
Boolean props like `isThread`, `isEditing`, `isDMThread` double possible states per flag and create exponential conditional logic. Composition patterns provide an alternative by extracting explicit variants.
|
|
16
|
+
|
|
17
|
+
**Incorrect: boolean props create exponential complexity**
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
function Composer({
|
|
21
|
+
onSubmit,
|
|
22
|
+
isThread,
|
|
23
|
+
channelId,
|
|
24
|
+
isDMThread,
|
|
25
|
+
dmId,
|
|
26
|
+
isEditing,
|
|
27
|
+
isForwarding,
|
|
28
|
+
}: Props) {
|
|
29
|
+
return (
|
|
30
|
+
<form>
|
|
31
|
+
<Header />
|
|
32
|
+
<Input />
|
|
33
|
+
{isDMThread ? (
|
|
34
|
+
<AlsoSendToDMField id={dmId} />
|
|
35
|
+
) : isThread ? (
|
|
36
|
+
<AlsoSendToChannelField id={channelId} />
|
|
37
|
+
) : null}
|
|
38
|
+
{isEditing ? (
|
|
39
|
+
<EditActions />
|
|
40
|
+
) : isForwarding ? (
|
|
41
|
+
<ForwardActions />
|
|
42
|
+
) : (
|
|
43
|
+
<DefaultActions />
|
|
44
|
+
)}
|
|
45
|
+
<Footer onSubmit={onSubmit} />
|
|
46
|
+
</form>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Correct: composition eliminates conditionals**
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
function ChannelComposer() {
|
|
55
|
+
return (
|
|
56
|
+
<Composer.Frame>
|
|
57
|
+
<Composer.Header />
|
|
58
|
+
<Composer.Input />
|
|
59
|
+
<Composer.Footer>
|
|
60
|
+
<Composer.Attachments />
|
|
61
|
+
<Composer.Formatting />
|
|
62
|
+
<Composer.Emojis />
|
|
63
|
+
<Composer.Submit />
|
|
64
|
+
</Composer.Footer>
|
|
65
|
+
</Composer.Frame>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function ThreadComposer({ channelId }: { channelId: string }) {
|
|
70
|
+
return (
|
|
71
|
+
<Composer.Frame>
|
|
72
|
+
<Composer.Header />
|
|
73
|
+
<Composer.Input />
|
|
74
|
+
<AlsoSendToChannelField id={channelId} />
|
|
75
|
+
<Composer.Footer>
|
|
76
|
+
<Composer.Formatting />
|
|
77
|
+
<Composer.Emojis />
|
|
78
|
+
<Composer.Submit />
|
|
79
|
+
</Composer.Footer>
|
|
80
|
+
</Composer.Frame>
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function EditComposer() {
|
|
85
|
+
return (
|
|
86
|
+
<Composer.Frame>
|
|
87
|
+
<Composer.Input />
|
|
88
|
+
<Composer.Footer>
|
|
89
|
+
<Composer.Formatting />
|
|
90
|
+
<Composer.Emojis />
|
|
91
|
+
<Composer.CancelEdit />
|
|
92
|
+
<Composer.SaveEdit />
|
|
93
|
+
</Composer.Footer>
|
|
94
|
+
</Composer.Frame>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Each variant is explicit about what it renders. Share internals without sharing a single monolithic parent.
|
|
100
|
+
|
|
101
|
+
### 1.2 Use Compound Components
|
|
102
|
+
|
|
103
|
+
**Impact: HIGH**
|
|
104
|
+
|
|
105
|
+
Compound components structure complex UI with a shared context. Each subcomponent accesses shared state via context, not props.
|
|
106
|
+
|
|
107
|
+
**Incorrect: monolithic component with render props**
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
function Composer({
|
|
111
|
+
renderHeader,
|
|
112
|
+
renderFooter,
|
|
113
|
+
renderActions,
|
|
114
|
+
showAttachments,
|
|
115
|
+
showFormatting,
|
|
116
|
+
showEmojis,
|
|
117
|
+
}: Props) {
|
|
118
|
+
return (
|
|
119
|
+
<form>
|
|
120
|
+
{renderHeader?.()}
|
|
121
|
+
<Input />
|
|
122
|
+
{showAttachments && <Attachments />}
|
|
123
|
+
{renderFooter ? (
|
|
124
|
+
renderFooter()
|
|
125
|
+
) : (
|
|
126
|
+
<Footer>
|
|
127
|
+
{showFormatting && <Formatting />}
|
|
128
|
+
{showEmojis && <Emojis />}
|
|
129
|
+
{renderActions?.()}
|
|
130
|
+
</Footer>
|
|
131
|
+
)}
|
|
132
|
+
</form>
|
|
133
|
+
)
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Correct: compound components with shared context**
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
const ComposerContext = createContext<ComposerContextValue | null>(null)
|
|
141
|
+
|
|
142
|
+
function ComposerProvider({ children, state, actions, meta }: ProviderProps) {
|
|
143
|
+
return (
|
|
144
|
+
<ComposerContext value={{ state, actions, meta }}>
|
|
145
|
+
{children}
|
|
146
|
+
</ComposerContext>
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function ComposerFrame({ children }: { children: React.ReactNode }) {
|
|
151
|
+
return <form>{children}</form>
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function ComposerInput() {
|
|
155
|
+
const {
|
|
156
|
+
state,
|
|
157
|
+
actions: { update },
|
|
158
|
+
meta: { inputRef },
|
|
159
|
+
} = use(ComposerContext)
|
|
160
|
+
return (
|
|
161
|
+
<input
|
|
162
|
+
ref={inputRef}
|
|
163
|
+
value={state.input}
|
|
164
|
+
onChange={(e) => update((s) => ({ ...s, input: e.target.value }))}
|
|
165
|
+
/>
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function ComposerSubmit() {
|
|
170
|
+
const {
|
|
171
|
+
actions: { submit },
|
|
172
|
+
} = use(ComposerContext)
|
|
173
|
+
return <button onClick={submit}>Send</button>
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const Composer = {
|
|
177
|
+
Provider: ComposerProvider,
|
|
178
|
+
Frame: ComposerFrame,
|
|
179
|
+
Input: ComposerInput,
|
|
180
|
+
Submit: ComposerSubmit,
|
|
181
|
+
Header: ComposerHeader,
|
|
182
|
+
Footer: ComposerFooter,
|
|
183
|
+
Attachments: ComposerAttachments,
|
|
184
|
+
Formatting: ComposerFormatting,
|
|
185
|
+
Emojis: ComposerEmojis,
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Usage:**
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
<Composer.Provider state={state} actions={actions} meta={meta}>
|
|
193
|
+
<Composer.Frame>
|
|
194
|
+
<Composer.Header />
|
|
195
|
+
<Composer.Input />
|
|
196
|
+
<Composer.Footer>
|
|
197
|
+
<Composer.Formatting />
|
|
198
|
+
<Composer.Submit />
|
|
199
|
+
</Composer.Footer>
|
|
200
|
+
</Composer.Frame>
|
|
201
|
+
</Composer.Provider>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## 2. State Management
|
|
207
|
+
|
|
208
|
+
**Impact: MEDIUM**
|
|
209
|
+
|
|
210
|
+
### 2.1 Decouple State Management from UI
|
|
211
|
+
|
|
212
|
+
**Impact: MEDIUM**
|
|
213
|
+
|
|
214
|
+
The provider is the single location that manages state. UI components consume the context interface — agnostic to whether state comes from `useState`, Zustand, or a server sync.
|
|
215
|
+
|
|
216
|
+
**Incorrect: UI coupled to state implementation**
|
|
217
|
+
|
|
218
|
+
```tsx
|
|
219
|
+
function ChannelComposer({ channelId }: { channelId: string }) {
|
|
220
|
+
const state = useGlobalChannelState(channelId)
|
|
221
|
+
const { submit, updateInput } = useChannelSync(channelId)
|
|
222
|
+
|
|
223
|
+
return (
|
|
224
|
+
<Composer.Frame>
|
|
225
|
+
<Composer.Input
|
|
226
|
+
value={state.input}
|
|
227
|
+
onChange={(text) => sync.updateInput(text)}
|
|
228
|
+
/>
|
|
229
|
+
<Composer.Submit onPress={() => sync.submit()} />
|
|
230
|
+
</Composer.Frame>
|
|
231
|
+
)
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
**Correct: state management isolated in provider**
|
|
236
|
+
|
|
237
|
+
```tsx
|
|
238
|
+
function ChannelProvider({
|
|
239
|
+
channelId,
|
|
240
|
+
children,
|
|
241
|
+
}: {
|
|
242
|
+
channelId: string
|
|
243
|
+
children: React.ReactNode
|
|
244
|
+
}) {
|
|
245
|
+
const { state, update, submit } = useGlobalChannel(channelId)
|
|
246
|
+
const inputRef = useRef(null)
|
|
247
|
+
|
|
248
|
+
return (
|
|
249
|
+
<Composer.Provider
|
|
250
|
+
state={state}
|
|
251
|
+
actions={{ update, submit }}
|
|
252
|
+
meta={{ inputRef }}
|
|
253
|
+
>
|
|
254
|
+
{children}
|
|
255
|
+
</Composer.Provider>
|
|
256
|
+
)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function ChannelComposer() {
|
|
260
|
+
return (
|
|
261
|
+
<Composer.Frame>
|
|
262
|
+
<Composer.Header />
|
|
263
|
+
<Composer.Input />
|
|
264
|
+
<Composer.Footer>
|
|
265
|
+
<Composer.Submit />
|
|
266
|
+
</Composer.Footer>
|
|
267
|
+
</Composer.Frame>
|
|
268
|
+
)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function Channel({ channelId }: { channelId: string }) {
|
|
272
|
+
return (
|
|
273
|
+
<ChannelProvider channelId={channelId}>
|
|
274
|
+
<ChannelComposer />
|
|
275
|
+
</ChannelProvider>
|
|
276
|
+
)
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**Different providers, same UI:**
|
|
281
|
+
|
|
282
|
+
```tsx
|
|
283
|
+
// Local state for ephemeral forms
|
|
284
|
+
function ForwardMessageProvider({ children }) {
|
|
285
|
+
const [state, setState] = useState(initialState)
|
|
286
|
+
const forwardMessage = useForwardMessage()
|
|
287
|
+
|
|
288
|
+
return (
|
|
289
|
+
<Composer.Provider
|
|
290
|
+
state={state}
|
|
291
|
+
actions={{ update: setState, submit: forwardMessage }}
|
|
292
|
+
>
|
|
293
|
+
{children}
|
|
294
|
+
</Composer.Provider>
|
|
295
|
+
)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Global synced state for channels
|
|
299
|
+
function ChannelProvider({ channelId, children }) {
|
|
300
|
+
const { state, update, submit } = useGlobalChannel(channelId)
|
|
301
|
+
|
|
302
|
+
return (
|
|
303
|
+
<Composer.Provider state={state} actions={{ update, submit }}>
|
|
304
|
+
{children}
|
|
305
|
+
</Composer.Provider>
|
|
306
|
+
)
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### 2.2 Define Generic Context Interfaces for Dependency Injection
|
|
311
|
+
|
|
312
|
+
**Impact: HIGH**
|
|
313
|
+
|
|
314
|
+
A generic interface with `state`, `actions`, and `meta` enables any provider to implement it — the same UI components work with different state implementations.
|
|
315
|
+
|
|
316
|
+
**Core pattern:** Lifted state, composed internals, dependency-injectable state.
|
|
317
|
+
|
|
318
|
+
**Incorrect: UI coupled to specific state implementation**
|
|
319
|
+
|
|
320
|
+
```tsx
|
|
321
|
+
function ComposerInput() {
|
|
322
|
+
const { input, setInput } = useChannelComposerState()
|
|
323
|
+
return <input value={input} onChange={(e) => setInput(e.target.value)} />
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**Correct: generic interface enables dependency injection**
|
|
328
|
+
|
|
329
|
+
```tsx
|
|
330
|
+
interface ComposerState {
|
|
331
|
+
input: string
|
|
332
|
+
attachments: Attachment[]
|
|
333
|
+
isSubmitting: boolean
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
interface ComposerActions {
|
|
337
|
+
update: (updater: (state: ComposerState) => ComposerState) => void
|
|
338
|
+
submit: () => void
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
interface ComposerMeta {
|
|
342
|
+
inputRef: React.RefObject<HTMLInputElement>
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
interface ComposerContextValue {
|
|
346
|
+
state: ComposerState
|
|
347
|
+
actions: ComposerActions
|
|
348
|
+
meta: ComposerMeta
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const ComposerContext = createContext<ComposerContextValue | null>(null)
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
**UI components consume the interface, not the implementation:**
|
|
355
|
+
|
|
356
|
+
```tsx
|
|
357
|
+
function ComposerInput() {
|
|
358
|
+
const {
|
|
359
|
+
state,
|
|
360
|
+
actions: { update },
|
|
361
|
+
meta,
|
|
362
|
+
} = use(ComposerContext)
|
|
363
|
+
|
|
364
|
+
return (
|
|
365
|
+
<input
|
|
366
|
+
ref={meta.inputRef}
|
|
367
|
+
value={state.input}
|
|
368
|
+
onChange={(e) => update((s) => ({ ...s, input: e.target.value }))}
|
|
369
|
+
/>
|
|
370
|
+
)
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
**Different providers implement the same interface:**
|
|
375
|
+
|
|
376
|
+
```tsx
|
|
377
|
+
// Provider A: Local state for ephemeral forms
|
|
378
|
+
function ForwardMessageProvider({ children }: { children: React.ReactNode }) {
|
|
379
|
+
const [state, setState] = useState(initialState)
|
|
380
|
+
const inputRef = useRef(null)
|
|
381
|
+
const submit = useForwardMessage()
|
|
382
|
+
|
|
383
|
+
return (
|
|
384
|
+
<ComposerContext
|
|
385
|
+
value={{
|
|
386
|
+
state,
|
|
387
|
+
actions: { update: setState, submit },
|
|
388
|
+
meta: { inputRef },
|
|
389
|
+
}}
|
|
390
|
+
>
|
|
391
|
+
{children}
|
|
392
|
+
</ComposerContext>
|
|
393
|
+
)
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Provider B: Global synced state for channels
|
|
397
|
+
function ChannelProvider({ channelId, children }: Props) {
|
|
398
|
+
const { state, update, submit } = useGlobalChannel(channelId)
|
|
399
|
+
const inputRef = useRef(null)
|
|
400
|
+
|
|
401
|
+
return (
|
|
402
|
+
<ComposerContext
|
|
403
|
+
value={{
|
|
404
|
+
state,
|
|
405
|
+
actions: { update, submit },
|
|
406
|
+
meta: { inputRef },
|
|
407
|
+
}}
|
|
408
|
+
>
|
|
409
|
+
{children}
|
|
410
|
+
</ComposerContext>
|
|
411
|
+
)
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
**Custom UI outside the component can access state and actions:**
|
|
416
|
+
|
|
417
|
+
```tsx
|
|
418
|
+
function ForwardMessageDialog() {
|
|
419
|
+
return (
|
|
420
|
+
<ForwardMessageProvider>
|
|
421
|
+
<Dialog>
|
|
422
|
+
<Composer.Frame>
|
|
423
|
+
<Composer.Input placeholder="Add a message, if you'd like." />
|
|
424
|
+
<Composer.Footer>
|
|
425
|
+
<Composer.Formatting />
|
|
426
|
+
<Composer.Emojis />
|
|
427
|
+
</Composer.Footer>
|
|
428
|
+
</Composer.Frame>
|
|
429
|
+
|
|
430
|
+
<MessagePreview />
|
|
431
|
+
|
|
432
|
+
<DialogActions>
|
|
433
|
+
<CancelButton />
|
|
434
|
+
<ForwardButton />
|
|
435
|
+
</DialogActions>
|
|
436
|
+
</Dialog>
|
|
437
|
+
</ForwardMessageProvider>
|
|
438
|
+
)
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function ForwardButton() {
|
|
442
|
+
const {
|
|
443
|
+
actions: { submit },
|
|
444
|
+
} = use(ComposerContext)
|
|
445
|
+
return <button onClick={submit}>Forward</button>
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function MessagePreview() {
|
|
449
|
+
const { state } = use(ComposerContext)
|
|
450
|
+
return <Preview message={state.input} attachments={state.attachments} />
|
|
451
|
+
}
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
The provider boundary is what matters — not the visual nesting. Components that need shared state just need to be within the provider.
|
|
455
|
+
|
|
456
|
+
### 2.3 Lift State into Provider Components
|
|
457
|
+
|
|
458
|
+
**Impact: HIGH**
|
|
459
|
+
|
|
460
|
+
Dedicated provider components hold state management. Sibling components outside the main UI access and modify state without prop drilling.
|
|
461
|
+
|
|
462
|
+
**Incorrect: state trapped inside component**
|
|
463
|
+
|
|
464
|
+
```tsx
|
|
465
|
+
function ForwardMessageComposer() {
|
|
466
|
+
const [state, setState] = useState(initialState)
|
|
467
|
+
const forwardMessage = useForwardMessage()
|
|
468
|
+
|
|
469
|
+
return (
|
|
470
|
+
<Composer.Frame>
|
|
471
|
+
<Composer.Input />
|
|
472
|
+
<Composer.Footer />
|
|
473
|
+
</Composer.Frame>
|
|
474
|
+
)
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// Problem: How does this button access composer state?
|
|
478
|
+
function ForwardMessageDialog() {
|
|
479
|
+
return (
|
|
480
|
+
<Dialog>
|
|
481
|
+
<ForwardMessageComposer />
|
|
482
|
+
<MessagePreview /> {/* Needs composer state */}
|
|
483
|
+
<DialogActions>
|
|
484
|
+
<CancelButton />
|
|
485
|
+
<ForwardButton /> {/* Needs to call submit */}
|
|
486
|
+
</DialogActions>
|
|
487
|
+
</Dialog>
|
|
488
|
+
)
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
**Correct: state lifted to provider**
|
|
493
|
+
|
|
494
|
+
```tsx
|
|
495
|
+
function ForwardMessageProvider({ children }: { children: React.ReactNode }) {
|
|
496
|
+
const [state, setState] = useState(initialState)
|
|
497
|
+
const forwardMessage = useForwardMessage()
|
|
498
|
+
const inputRef = useRef(null)
|
|
499
|
+
|
|
500
|
+
return (
|
|
501
|
+
<Composer.Provider
|
|
502
|
+
state={state}
|
|
503
|
+
actions={{ update: setState, submit: forwardMessage }}
|
|
504
|
+
meta={{ inputRef }}
|
|
505
|
+
>
|
|
506
|
+
{children}
|
|
507
|
+
</Composer.Provider>
|
|
508
|
+
)
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
function ForwardMessageDialog() {
|
|
512
|
+
return (
|
|
513
|
+
<ForwardMessageProvider>
|
|
514
|
+
<Dialog>
|
|
515
|
+
<ForwardMessageComposer />
|
|
516
|
+
<MessagePreview />
|
|
517
|
+
<DialogActions>
|
|
518
|
+
<CancelButton />
|
|
519
|
+
<ForwardButton />
|
|
520
|
+
</DialogActions>
|
|
521
|
+
</Dialog>
|
|
522
|
+
</ForwardMessageProvider>
|
|
523
|
+
)
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function ForwardButton() {
|
|
527
|
+
const { actions } = use(Composer.Context)
|
|
528
|
+
return <button onClick={actions.submit}>Forward</button>
|
|
529
|
+
}
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
**Key insight:** Components that need shared state don't have to be visually nested inside each other — they just need to be within the same provider.
|
|
533
|
+
|
|
534
|
+
---
|
|
535
|
+
|
|
536
|
+
## 3. Implementation Patterns
|
|
537
|
+
|
|
538
|
+
**Impact: MEDIUM**
|
|
539
|
+
|
|
540
|
+
### 3.1 Create Explicit Component Variants
|
|
541
|
+
|
|
542
|
+
**Impact: MEDIUM**
|
|
543
|
+
|
|
544
|
+
Explicit variant components replace a single component with many boolean props. Each variant composes the pieces it needs.
|
|
545
|
+
|
|
546
|
+
**Incorrect: one component, many modes**
|
|
547
|
+
|
|
548
|
+
```tsx
|
|
549
|
+
<Composer
|
|
550
|
+
isThread
|
|
551
|
+
isEditing={false}
|
|
552
|
+
channelId='abc'
|
|
553
|
+
showAttachments
|
|
554
|
+
showFormatting={false}
|
|
555
|
+
/>
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
**Correct: explicit variants**
|
|
559
|
+
|
|
560
|
+
```tsx
|
|
561
|
+
<ThreadComposer channelId="abc" />
|
|
562
|
+
<EditMessageComposer messageId="xyz" />
|
|
563
|
+
<ForwardMessageComposer messageId="123" />
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
**Implementation:**
|
|
567
|
+
|
|
568
|
+
```tsx
|
|
569
|
+
function ThreadComposer({ channelId }: { channelId: string }) {
|
|
570
|
+
return (
|
|
571
|
+
<ThreadProvider channelId={channelId}>
|
|
572
|
+
<Composer.Frame>
|
|
573
|
+
<Composer.Input />
|
|
574
|
+
<AlsoSendToChannelField channelId={channelId} />
|
|
575
|
+
<Composer.Footer>
|
|
576
|
+
<Composer.Formatting />
|
|
577
|
+
<Composer.Emojis />
|
|
578
|
+
<Composer.Submit />
|
|
579
|
+
</Composer.Footer>
|
|
580
|
+
</Composer.Frame>
|
|
581
|
+
</ThreadProvider>
|
|
582
|
+
)
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
function EditMessageComposer({ messageId }: { messageId: string }) {
|
|
586
|
+
return (
|
|
587
|
+
<EditMessageProvider messageId={messageId}>
|
|
588
|
+
<Composer.Frame>
|
|
589
|
+
<Composer.Input />
|
|
590
|
+
<Composer.Footer>
|
|
591
|
+
<Composer.Formatting />
|
|
592
|
+
<Composer.Emojis />
|
|
593
|
+
<Composer.CancelEdit />
|
|
594
|
+
<Composer.SaveEdit />
|
|
595
|
+
</Composer.Footer>
|
|
596
|
+
</Composer.Frame>
|
|
597
|
+
</EditMessageProvider>
|
|
598
|
+
)
|
|
599
|
+
}
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
Each variant is explicit about what provider/state it uses, what UI elements it includes, and what actions are available.
|
|
603
|
+
|
|
604
|
+
### 3.2 Children vs Render Props
|
|
605
|
+
|
|
606
|
+
**Impact: MEDIUM**
|
|
607
|
+
|
|
608
|
+
`children` provides composition for static structure; `renderX` props are suited for cases where the parent passes data back to the child.
|
|
609
|
+
|
|
610
|
+
**Incorrect: render props**
|
|
611
|
+
|
|
612
|
+
```tsx
|
|
613
|
+
<Composer
|
|
614
|
+
renderHeader={() => <CustomHeader />}
|
|
615
|
+
renderFooter={() => (
|
|
616
|
+
<>
|
|
617
|
+
<Formatting />
|
|
618
|
+
<Emojis />
|
|
619
|
+
</>
|
|
620
|
+
)}
|
|
621
|
+
renderActions={() => <SubmitButton />}
|
|
622
|
+
/>
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
**Correct: compound components with children**
|
|
626
|
+
|
|
627
|
+
```tsx
|
|
628
|
+
<Composer.Frame>
|
|
629
|
+
<CustomHeader />
|
|
630
|
+
<Composer.Input />
|
|
631
|
+
<Composer.Footer>
|
|
632
|
+
<Composer.Formatting />
|
|
633
|
+
<Composer.Emojis />
|
|
634
|
+
<SubmitButton />
|
|
635
|
+
</Composer.Footer>
|
|
636
|
+
</Composer.Frame>
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
**When render props are appropriate:**
|
|
640
|
+
|
|
641
|
+
```tsx
|
|
642
|
+
// Render props work well when you need to pass data back
|
|
643
|
+
<List
|
|
644
|
+
data={items}
|
|
645
|
+
renderItem={({ item, index }) => <Item item={item} index={index} />}
|
|
646
|
+
/>
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
Use render props when the parent needs to provide data to the child. Use children when composing static structure.
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
653
|
+
## 4. React 19 APIs
|
|
654
|
+
|
|
655
|
+
**Impact: MEDIUM**
|
|
656
|
+
|
|
657
|
+
### 4.1 React 19 API Changes
|
|
658
|
+
|
|
659
|
+
> **React 19+ only.** These patterns require React 19.
|
|
660
|
+
|
|
661
|
+
**ref is a regular prop (no forwardRef)**
|
|
662
|
+
|
|
663
|
+
```tsx
|
|
664
|
+
// ❌ Don't use forwardRef in React 19
|
|
665
|
+
const ComposerInput = forwardRef<HTMLInputElement, Props>((props, ref) => {
|
|
666
|
+
return <input ref={ref} {...props} />
|
|
667
|
+
})
|
|
668
|
+
|
|
669
|
+
// ✅ ref as a regular prop
|
|
670
|
+
function ComposerInput({ ref, ...props }: Props & { ref?: React.Ref<HTMLInputElement> }) {
|
|
671
|
+
return <input ref={ref} {...props} />
|
|
672
|
+
}
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
**use() replaces useContext()**
|
|
676
|
+
|
|
677
|
+
```tsx
|
|
678
|
+
// ❌ Don't use useContext in React 19
|
|
679
|
+
const value = useContext(MyContext)
|
|
680
|
+
|
|
681
|
+
// ✅ use() — can also be called conditionally
|
|
682
|
+
const value = use(MyContext)
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
`use()` can also unwrap promises, enabling new data fetching patterns with Suspense:
|
|
686
|
+
|
|
687
|
+
```tsx
|
|
688
|
+
function DataDisplay({ dataPromise }: { dataPromise: Promise<Data> }) {
|
|
689
|
+
const data = use(dataPromise)
|
|
690
|
+
return <div>{data.content}</div>
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
function Page() {
|
|
694
|
+
const dataPromise = fetchData()
|
|
695
|
+
return (
|
|
696
|
+
<Suspense fallback={<Skeleton />}>
|
|
697
|
+
<DataDisplay dataPromise={dataPromise} />
|
|
698
|
+
</Suspense>
|
|
699
|
+
)
|
|
700
|
+
}
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
---
|
|
704
|
+
|
|
705
|
+
## References
|
|
706
|
+
|
|
707
|
+
1. [https://react.dev](https://react.dev)
|
|
708
|
+
2. [https://react.dev/learn/passing-data-deeply-with-context](https://react.dev/learn/passing-data-deeply-with-context)
|
|
709
|
+
3. [https://react.dev/reference/react/use](https://react.dev/reference/react/use)
|