mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
fix(linter): treat Reanimated shared values as ref-like in React Compiler rules
Closes #26222
This commit is contained in:
1 parent
22923f274e
commit
4c9d5aa496
5 files changed
+89
No files matched your search
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"categories": { "correctness": "off" },
|
||||
"plugins": ["react"],
|
||||
"rules": { "react/immutability": "error", "react/refs": "error" }
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { useEffect } from "react";
|
||||
import { Gesture } from "react-native-gesture-handler";
|
||||
import { useSharedValue, withSpring, withTiming } from "react-native-reanimated";
|
||||
|
||||
// Shared values imported from Reanimated are ref-like, so writing them outside
|
||||
// of render is allowed.
|
||||
export function SomeComponent() {
|
||||
const sharedVal = useSharedValue(0);
|
||||
return <Button onPress={() => (sharedVal.value = Math.random())} title="Randomize" />;
|
||||
}
|
||||
|
||||
export function usePressToGrow() {
|
||||
const width = useSharedValue(100);
|
||||
return () => {
|
||||
width.value = withSpring(width.value + 50);
|
||||
};
|
||||
}
|
||||
|
||||
export function useFadeIn(visible: boolean) {
|
||||
const opacity = useSharedValue(0);
|
||||
useEffect(() => {
|
||||
opacity.value = withTiming(visible ? 1 : 0);
|
||||
}, [opacity, visible]);
|
||||
return opacity;
|
||||
}
|
||||
|
||||
export function useDrag() {
|
||||
const offset = useSharedValue(0);
|
||||
return Gesture.Pan()
|
||||
.onChange((event) => {
|
||||
offset.value += event.changeX;
|
||||
})
|
||||
.onFinalize(() => {
|
||||
offset.value = withSpring(0);
|
||||
});
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// A global `useSharedValue` is an unknown hook, so writing its result is still
|
||||
// reported.
|
||||
export function SomeComponent() {
|
||||
const sharedVal = useSharedValue(0);
|
||||
return <Button onPress={() => (sharedVal.value = Math.random())} title="Randomize" />;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# Exit code
|
||||
1
|
||||
|
||||
# stdout
|
||||
```
|
||||
x react(immutability): Cannot modify local variables after render completes
|
||||
,-[files/non-imported.jsx:5:34]
|
||||
4 | const sharedVal = useSharedValue(0);
|
||||
5 | return <Button onPress={() => (sharedVal.value = Math.random())} title="Randomize" />;
|
||||
: ^| ^^^^|^^^^
|
||||
: | `-- This modifies `sharedVal`
|
||||
: `-- This function may (indirectly) reassign or modify `sharedVal` after render
|
||||
6 | }
|
||||
`----
|
||||
help: This argument is a function which may reassign or mutate `sharedVal` after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
|
||||
note: React Compiler skipped optimizing this component or hook. Additional guidance: https://react.dev/reference/eslint-plugin-react-hooks/lints/immutability
|
||||
|
||||
x react(immutability): This value cannot be modified
|
||||
,-[files/non-imported.jsx:5:34]
|
||||
3 | export function SomeComponent() {
|
||||
4 | const sharedVal = useSharedValue(0);
|
||||
: ^^^^|^^^^
|
||||
: `-- `sharedVal` originates here
|
||||
5 | return <Button onPress={() => (sharedVal.value = Math.random())} title="Randomize" />;
|
||||
: ^^^^|^^^^
|
||||
: `-- `sharedVal` cannot be modified
|
||||
6 | }
|
||||
`----
|
||||
help: Modifying a value returned from a hook is not allowed. Consider moving the modification into the hook where the value is constructed
|
||||
note: React Compiler skipped optimizing this component or hook. Additional guidance: https://react.dev/reference/eslint-plugin-react-hooks/lints/immutability
|
||||
|
||||
Found 0 warnings and 2 errors.
|
||||
Finished in Xms on 2 files with 2 rules using X threads.
|
||||
```
|
||||
|
||||
# stderr
|
||||
```
|
||||
```
|
||||
@@ -69,6 +69,10 @@ fn react_compiler_plugin_options(env_options: &ReactCompilerEnvOptions) -> Plugi
|
||||
validate_no_derived_computations_in_effects: true,
|
||||
validate_exhaustive_memoization_dependencies: true,
|
||||
validate_exhaustive_effect_dependencies: ExhaustiveEffectDepsMode::All,
|
||||
// The Babel plugin enables this when it detects `react-native-reanimated`, which
|
||||
// Oxlint cannot do without a plugin list or resolver. The type model only applies
|
||||
// to values imported from `react-native-reanimated`, so enabling it is safe.
|
||||
enable_custom_type_definition_for_reanimated: true,
|
||||
..EnvironmentConfig::default()
|
||||
},
|
||||
lint_skip_reactive_scope_passes: !env_options.report_todo_and_invariant,
|
||||
|
||||
Reference in new issue
Block a user