mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 12:20:20 +01:00
[autodeps] Do not include nonreactive refs or setStates in inferred deps (#32236)
This commit is contained in:
parent
bdce84a539
commit
d4e24b349e
|
|
@ -15,6 +15,8 @@ import {
|
|||
ReactiveScopeDependency,
|
||||
Place,
|
||||
ReactiveScopeDependencies,
|
||||
isUseRefType,
|
||||
isSetStateType,
|
||||
} from '../HIR';
|
||||
import {DEFAULT_EXPORT} from '../HIR/Environment';
|
||||
import {
|
||||
|
|
@ -181,11 +183,20 @@ export function inferEffectDependencies(fn: HIRFunction): void {
|
|||
/**
|
||||
* Step 1: push dependencies to the effect deps array
|
||||
*
|
||||
* Note that it's invalid to prune non-reactive deps in this pass, see
|
||||
* Note that it's invalid to prune all non-reactive deps in this pass, see
|
||||
* the `infer-effect-deps/pruned-nonreactive-obj` fixture for an
|
||||
* explanation.
|
||||
*/
|
||||
for (const dep of scopeInfo.deps) {
|
||||
if (
|
||||
(isUseRefType(dep.identifier) ||
|
||||
isSetStateType(dep.identifier)) &&
|
||||
!reactiveIds.has(dep.identifier.id)
|
||||
) {
|
||||
// exclude non-reactive hook results, which will never be in a memo block
|
||||
continue;
|
||||
}
|
||||
|
||||
const {place, instructions} = writeDependencyToInstructions(
|
||||
dep,
|
||||
reactiveIds.has(dep.identifier.id),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies
|
||||
import {useEffect, useRef} from 'react';
|
||||
function useCustomRef() {
|
||||
const ref = useRef();
|
||||
return ref;
|
||||
}
|
||||
function NonReactiveWrapper() {
|
||||
const ref = useCustomRef();
|
||||
useEffect(() => {
|
||||
print(ref);
|
||||
});
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
|
||||
import { useEffect, useRef } from "react";
|
||||
function useCustomRef() {
|
||||
const ref = useRef();
|
||||
return ref;
|
||||
}
|
||||
|
||||
function NonReactiveWrapper() {
|
||||
const $ = _c(2);
|
||||
const ref = useCustomRef();
|
||||
let t0;
|
||||
if ($[0] !== ref) {
|
||||
t0 = () => {
|
||||
print(ref);
|
||||
};
|
||||
$[0] = ref;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
useEffect(t0, [ref]);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// @inferEffectDependencies
|
||||
import {useEffect, useRef} from 'react';
|
||||
function useCustomRef() {
|
||||
const ref = useRef();
|
||||
return ref;
|
||||
}
|
||||
function NonReactiveWrapper() {
|
||||
const ref = useCustomRef();
|
||||
useEffect(() => {
|
||||
print(ref);
|
||||
});
|
||||
}
|
||||
|
|
@ -101,7 +101,6 @@ function Component(t0) {
|
|||
useEffect(t3, [
|
||||
foo,
|
||||
bar,
|
||||
ref,
|
||||
localNonPrimitiveReactive,
|
||||
localNonPrimitiveNonreactive,
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ function NonReactiveRefInEffect() {
|
|||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
useEffect(t0, [ref]);
|
||||
useEffect(t0, []);
|
||||
}
|
||||
|
||||
```
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies
|
||||
import {useEffect, useState} from 'react';
|
||||
import {print} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Special case of `infer-effect-deps/nonreactive-dep`.
|
||||
*
|
||||
* We know that local `useRef` return values are stable, regardless of
|
||||
* inferred memoization.
|
||||
*/
|
||||
function NonReactiveSetStateInEffect() {
|
||||
const [_, setState] = useState('initial value');
|
||||
useEffect(() => print(setState));
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
|
||||
import { useEffect, useState } from "react";
|
||||
import { print } from "shared-runtime";
|
||||
|
||||
/**
|
||||
* Special case of `infer-effect-deps/nonreactive-dep`.
|
||||
*
|
||||
* We know that local `useRef` return values are stable, regardless of
|
||||
* inferred memoization.
|
||||
*/
|
||||
function NonReactiveSetStateInEffect() {
|
||||
const $ = _c(1);
|
||||
const [, setState] = useState("initial value");
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = () => print(setState);
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
useEffect(t0, []);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// @inferEffectDependencies
|
||||
import {useEffect, useState} from 'react';
|
||||
import {print} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Special case of `infer-effect-deps/nonreactive-dep`.
|
||||
*
|
||||
* We know that local `useRef` return values are stable, regardless of
|
||||
* inferred memoization.
|
||||
*/
|
||||
function NonReactiveSetStateInEffect() {
|
||||
const [_, setState] = useState('initial value');
|
||||
useEffect(() => print(setState));
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies
|
||||
import {useEffect, useRef} from 'react';
|
||||
import {print} from 'shared-runtime';
|
||||
|
||||
/*
|
||||
* Ref types are not enough to determine to omit from deps. Must also take reactivity into account.
|
||||
*/
|
||||
function ReactiveRefInEffect(props) {
|
||||
const ref1 = useRef('initial value');
|
||||
const ref2 = useRef('initial value');
|
||||
let ref;
|
||||
if (props.foo) {
|
||||
ref = ref1;
|
||||
} else {
|
||||
ref = ref2;
|
||||
}
|
||||
useEffect(() => print(ref));
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
|
||||
import { useEffect, useRef } from "react";
|
||||
import { print } from "shared-runtime";
|
||||
|
||||
/*
|
||||
* Ref types are not enough to determine to omit from deps. Must also take reactivity into account.
|
||||
*/
|
||||
function ReactiveRefInEffect(props) {
|
||||
const $ = _c(4);
|
||||
const ref1 = useRef("initial value");
|
||||
const ref2 = useRef("initial value");
|
||||
let ref;
|
||||
if ($[0] !== props.foo) {
|
||||
if (props.foo) {
|
||||
ref = ref1;
|
||||
} else {
|
||||
ref = ref2;
|
||||
}
|
||||
$[0] = props.foo;
|
||||
$[1] = ref;
|
||||
} else {
|
||||
ref = $[1];
|
||||
}
|
||||
let t0;
|
||||
if ($[2] !== ref) {
|
||||
t0 = () => print(ref);
|
||||
$[2] = ref;
|
||||
$[3] = t0;
|
||||
} else {
|
||||
t0 = $[3];
|
||||
}
|
||||
useEffect(t0, [ref]);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// @inferEffectDependencies
|
||||
import {useEffect, useRef} from 'react';
|
||||
import {print} from 'shared-runtime';
|
||||
|
||||
/*
|
||||
* Ref types are not enough to determine to omit from deps. Must also take reactivity into account.
|
||||
*/
|
||||
function ReactiveRefInEffect(props) {
|
||||
const ref1 = useRef('initial value');
|
||||
const ref2 = useRef('initial value');
|
||||
let ref;
|
||||
if (props.foo) {
|
||||
ref = ref1;
|
||||
} else {
|
||||
ref = ref2;
|
||||
}
|
||||
useEffect(() => print(ref));
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies
|
||||
import {useEffect, useState} from 'react';
|
||||
import {print} from 'shared-runtime';
|
||||
|
||||
/*
|
||||
* setState types are not enough to determine to omit from deps. Must also take reactivity into account.
|
||||
*/
|
||||
function ReactiveRefInEffect(props) {
|
||||
const [_state1, setState1] = useRef('initial value');
|
||||
const [_state2, setState2] = useRef('initial value');
|
||||
let setState;
|
||||
if (props.foo) {
|
||||
setState = setState1;
|
||||
} else {
|
||||
setState = setState2;
|
||||
}
|
||||
useEffect(() => print(setState));
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
|
||||
import { useEffect, useState } from "react";
|
||||
import { print } from "shared-runtime";
|
||||
|
||||
/*
|
||||
* setState types are not enough to determine to omit from deps. Must also take reactivity into account.
|
||||
*/
|
||||
function ReactiveRefInEffect(props) {
|
||||
const $ = _c(2);
|
||||
const [, setState1] = useRef("initial value");
|
||||
const [, setState2] = useRef("initial value");
|
||||
let setState;
|
||||
if (props.foo) {
|
||||
setState = setState1;
|
||||
} else {
|
||||
setState = setState2;
|
||||
}
|
||||
let t0;
|
||||
if ($[0] !== setState) {
|
||||
t0 = () => print(setState);
|
||||
$[0] = setState;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
useEffect(t0, [setState]);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// @inferEffectDependencies
|
||||
import {useEffect, useState} from 'react';
|
||||
import {print} from 'shared-runtime';
|
||||
|
||||
/*
|
||||
* setState types are not enough to determine to omit from deps. Must also take reactivity into account.
|
||||
*/
|
||||
function ReactiveRefInEffect(props) {
|
||||
const [_state1, setState1] = useRef('initial value');
|
||||
const [_state2, setState2] = useRef('initial value');
|
||||
let setState;
|
||||
if (props.foo) {
|
||||
setState = setState1;
|
||||
} else {
|
||||
setState = setState2;
|
||||
}
|
||||
useEffect(() => print(setState));
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user