create-mixins
Create @remix-run/component mixins using createMixin with lifecycle-first semantics. Use when adding new mixins with correct runtime behavior and type flow.
Installation
Suivez les instructions du dépôt pour votre agent. Consultez les fichiers et dépendances avant l’installation.
Voir la source ↗GuidesInstructions
Creating Mixins (@remix-run/component)
Use this skill when authoring new mixins in packages/component.
The key principle: model the real runtime contract first, then write the smallest code that matches it.
Core Runtime Semantics
Treat these as constraints, not suggestions:
- A mixin handle is tied to one mounted host node lifecycle.
-
insertis the host-node availability point for imperative setup. -
removeis teardown for that same lifecycle. -
queueTaskruns post-commit and receives(node, signal)for mixins. - Mixin render functions should stay pure; side effects belong in
insert,remove, or queued work.
createMixin<NodeType>((handle) => {
// Setup runs once per handle lifecycle.
handle.addEventListener('insert', (event) => {
// event.node is the mounted host node for this lifecycle.
// Attach imperative effects here.
})
handle.addEventListener('remove', () => {
// Teardown for the same lifecycle.
// Remove listeners, abort work, release resources.
})
return (props) => {
// Render stays pure: derive props/JSX only.
// Post-commit work goes in queueTask when needed.
handle.queueTask((node) => {
// Runs after commit with the concrete host node.
})
return <handle.element {...props} />
}
})
If your implementation assumes semantics that do not exist (node swapping, repeated insert for the same handle, etc.), remove that logic.
Authoring Rules
- Start with lifecycle truth:
- Use
insertfor attach/setup. - Use
removefor detach/cleanup.
- Use
- Keep state minimal and intentional:
- Do not keep mutable state "just in case" if runtime guarantees make it unnecessary.
- Be precise with defensive checks:
- Use
invariant(...)when a condition is guaranteed by runtime and violation means framework bug. - Use soft guards only when nullability is genuinely part of valid runtime flow.
- Use
- Use
queueTask((node, signal) => ...)for post-commit DOM work.- In most mixins, only
nodeis needed. - Reach for
signalonly when work is async or cancellation-sensitive.
- In most mixins, only
- Do not add
signal.abortedchecks for purely synchronous work. - Favor function expression for helpers in scope.
- Avoid speculative runtime assumptions.
Preferred Patterns
1) Pure prop transform mixin
let withTitle = createMixin((handle) => (title: string, props: { title?: string }) => (
<handle.element {...props} title={title} />
))
2) Lifecycle-managed imperative listener
let withFocus = createMixin<HTMLElement>((handle) => {
handle.addEventListener('insert', (event) => {
event.node.focus()
})
return (props) => <handle.element {...props} />
})
3) Post-commit rebind with node provided by queueTask
handle.queueTask((node) => {
node.removeEventListener(prevType, stableHandler, prevCapture)
node.addEventListener(nextType, stableHandler, nextCapture)
})
Anti-Patterns
- Adding state for hypothetical runtime scenarios.
- Broad defensive null checks where runtime guarantees presence.
- Mixing setup/cleanup side effects into render-only code paths.
- Using
signal.abortedin synchronous non-racy code as boilerplate. - Hiding semantic uncertainty with casts instead of fixing types/contracts.
Mixin Creation Checklist
- Runtime assumptions are stated and match reconciler behavior.
- Lifecycle wiring uses
insert/removedirectly. - State is minimal; no "might change later" scaffolding.
-
queueTaskused only where post-commit timing is required. - Type flow from
createMixin<ThisType>is preserved. - Tests cover ordering, teardown, and type inference contracts.
Exemples
Consultez les exemples du dépôt source.
Voir la source ↗Historique source
- Date d’indexation
- 2026-03-11
- Mise à jour de l’index
- 2026-03-11
- Branch
- main
Les dates concernent ce répertoire. Consultez le dépôt pour l’historique du code.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!