Skip to content

Commit 5380933

Browse files
committed
Allow using 'static*' props outside tracked scopes, but forbid passing reactive variables to them the caller.
1 parent 75a0dc7 commit 5380933

File tree

3 files changed

+40
-1
lines changed

3 files changed

+40
-1
lines changed

docs/reactivity.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,9 @@ const result = indexArray(array, (item) => {
387387
item();
388388
});
389389

390+
const [signal] = createSignal();
391+
let el = <Component staticProp={signal()} />;
392+
390393
```
391394

392395
### Valid Examples
@@ -719,6 +722,15 @@ function Component(props) {
719722
);
720723
}
721724

725+
function Component(props) {
726+
const value = props.staticValue;
727+
}
728+
729+
function Component() {
730+
const staticValue = () => props.value;
731+
const value = staticValue();
732+
}
733+
722734
```
723735
<!-- AUTO-GENERATED-CONTENT:END -->
724736

src/rules/reactivity.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ const rule: TSESLint.RuleModule<MessageIds, []> = {
547547
});
548548
} else if (
549549
parent.property.type === "Identifier" &&
550-
/^(?:initial|default)[A-Z]/.test(parent.property.name)
550+
/^(?:initial|default|static)[A-Z]/.test(parent.property.name)
551551
) {
552552
// We're using a prop with a name that starts with `initial` or
553553
// `default`, like `props.initialCount`. We'll refrain from warning
@@ -831,6 +831,18 @@ const rule: TSESLint.RuleModule<MessageIds, []> = {
831831
// rule will warn later.
832832
// TODO: add some kind of "anti- tracked scope" that still warns but enhances the error
833833
// message if matched.
834+
} else if (
835+
node.parent?.type === "JSXAttribute" &&
836+
node.parent.name?.type === "JSXIdentifier" &&
837+
/^static[A-Z]/.test(node.parent.name.name) &&
838+
node.parent.parent?.type === "JSXOpeningElement" &&
839+
node.parent.parent.name.type === "JSXIdentifier" &&
840+
!isDOMElementName(node.parent.parent.name.name)
841+
) {
842+
// A caller is passing a value to a prop prefixed with `static` in a component, i.e.
843+
// `<Box staticName={...} />`. Since we're considering these props as static in the component
844+
// we shouldn't allow passing reactive values to them, as this isn't just ignoring reactivity
845+
// like initial*/default*; this is disabling it altogether as a convention. Do nothing.
834846
} else if (
835847
node.parent?.type === "JSXAttribute" &&
836848
node.parent.name.name === "ref" &&

test/rules/reactivity.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,14 @@ export const cases = run("reactivity", rule, {
273273
}}</div>
274274
);
275275
}`,
276+
// static* prefix for props
277+
`function Component(props) {
278+
const value = props.staticValue;
279+
}`,
280+
`function Component() {
281+
const staticValue = () => props.value;
282+
const value = staticValue();
283+
}`,
276284
],
277285
invalid: [
278286
// Untracked signals
@@ -740,5 +748,12 @@ export const cases = run("reactivity", rule, {
740748
});`,
741749
errors: [{ messageId: "untrackedReactive", line: 4 }],
742750
},
751+
// static* prefix for props
752+
{
753+
code: `
754+
const [signal] = createSignal();
755+
let el = <Component staticProp={signal()} />;`,
756+
errors: [{ messageId: "untrackedReactive" }],
757+
},
743758
],
744759
});

0 commit comments

Comments
 (0)