Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c10461285a | ||
|
|
4c9faa3ec3 |
@@ -358,14 +358,8 @@ function recordInstructionDerivations(
|
||||
context.effects.add(effectFunction.loweredFunc.func);
|
||||
}
|
||||
} else if (isUseStateType(lvalue.identifier) && value.args.length > 0) {
|
||||
typeOfValue = 'fromState';
|
||||
context.derivationCache.addDerivationEntry(
|
||||
lvalue,
|
||||
new Set(),
|
||||
typeOfValue,
|
||||
true,
|
||||
);
|
||||
return;
|
||||
isSource = true;
|
||||
typeOfValue = joinValue(typeOfValue, 'fromState');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,26 +568,6 @@ function renderTree(
|
||||
return result;
|
||||
}
|
||||
|
||||
function getFnLocalDeps(
|
||||
fn: FunctionExpression | undefined,
|
||||
): Set<IdentifierId> | undefined {
|
||||
if (!fn) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const deps: Set<IdentifierId> = new Set();
|
||||
|
||||
for (const [, block] of fn.loweredFunc.func.body.blocks) {
|
||||
for (const instr of block.instructions) {
|
||||
if (instr.value.kind === 'LoadLocal') {
|
||||
deps.add(instr.value.place.identifier.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deps;
|
||||
}
|
||||
|
||||
function validateEffect(
|
||||
effectFunction: HIRFunction,
|
||||
context: ValidationContext,
|
||||
@@ -612,23 +586,8 @@ function validateEffect(
|
||||
Set<SourceLocation>
|
||||
> = new Map();
|
||||
|
||||
let cleanUpFunctionDeps: Set<IdentifierId> | undefined;
|
||||
|
||||
const globals: Set<IdentifierId> = new Set();
|
||||
for (const block of effectFunction.body.blocks.values()) {
|
||||
/*
|
||||
* if the block is in an effect and is of type return then its an effect's cleanup function
|
||||
* if the cleanup function depends on a value from which effect-set state is derived then
|
||||
* we can't validate
|
||||
*/
|
||||
if (
|
||||
block.terminal.kind === 'return' &&
|
||||
block.terminal.returnVariant === 'Explicit'
|
||||
) {
|
||||
cleanUpFunctionDeps = getFnLocalDeps(
|
||||
context.functions.get(block.terminal.value.identifier.id),
|
||||
);
|
||||
}
|
||||
for (const pred of block.preds) {
|
||||
if (!seenBlocks.has(pred)) {
|
||||
// skip if block has a back edge
|
||||
@@ -739,12 +698,6 @@ function validateEffect(
|
||||
),
|
||||
);
|
||||
|
||||
for (const dep of derivedSetStateCall.sourceIds) {
|
||||
if (cleanUpFunctionDeps !== undefined && cleanUpFunctionDeps.has(dep)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const propsArr = Array.from(propsSet);
|
||||
const stateArr = Array.from(stateSet);
|
||||
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
function Component(file: File) {
|
||||
const [imageUrl, setImageUrl] = useState(null);
|
||||
|
||||
/*
|
||||
* Cleaning up the variable or a source of the variable used to setState
|
||||
* inside the effect communicates that we always need to clean up something
|
||||
* which is a valid use case for useEffect. In which case we want to
|
||||
* avoid an throwing
|
||||
*/
|
||||
useEffect(() => {
|
||||
const imageUrlPrepared = URL.createObjectURL(file);
|
||||
setImageUrl(imageUrlPrepared);
|
||||
return () => URL.revokeObjectURL(imageUrlPrepared);
|
||||
}, [file]);
|
||||
|
||||
return <Image src={imageUrl} xstyle={styles.imageSizeLimits} />;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
function Component(file) {
|
||||
const $ = _c(5);
|
||||
const [imageUrl, setImageUrl] = useState(null);
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] !== file) {
|
||||
t0 = () => {
|
||||
const imageUrlPrepared = URL.createObjectURL(file);
|
||||
setImageUrl(imageUrlPrepared);
|
||||
return () => URL.revokeObjectURL(imageUrlPrepared);
|
||||
};
|
||||
t1 = [file];
|
||||
$[0] = file;
|
||||
$[1] = t0;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
t1 = $[2];
|
||||
}
|
||||
useEffect(t0, t1);
|
||||
let t2;
|
||||
if ($[3] !== imageUrl) {
|
||||
t2 = <Image src={imageUrl} xstyle={styles.imageSizeLimits} />;
|
||||
$[3] = imageUrl;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":108},"end":{"line":21,"column":1,"index":700},"filename":"effect-with-cleanup-function-depending-on-derived-computation-value.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented
|
||||
@@ -1,21 +0,0 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
function Component(file: File) {
|
||||
const [imageUrl, setImageUrl] = useState(null);
|
||||
|
||||
/*
|
||||
* Cleaning up the variable or a source of the variable used to setState
|
||||
* inside the effect communicates that we always need to clean up something
|
||||
* which is a valid use case for useEffect. In which case we want to
|
||||
* avoid an throwing
|
||||
*/
|
||||
useEffect(() => {
|
||||
const imageUrlPrepared = URL.createObjectURL(file);
|
||||
setImageUrl(imageUrlPrepared);
|
||||
return () => URL.revokeObjectURL(imageUrlPrepared);
|
||||
}, [file]);
|
||||
|
||||
return <Image src={imageUrl} xstyle={styles.imageSizeLimits} />;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp
|
||||
|
||||
function Component({ prop }) {
|
||||
const [s, setS] = useState(prop)
|
||||
const [second, setSecond] = useState(prop)
|
||||
|
||||
useEffect(() => {
|
||||
setS(second)
|
||||
}, [second])
|
||||
|
||||
return <div>{s}</div>
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(5);
|
||||
const { prop } = t0;
|
||||
const [s, setS] = useState(prop);
|
||||
const [second] = useState(prop);
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== second) {
|
||||
t1 = () => {
|
||||
setS(second);
|
||||
};
|
||||
t2 = [second];
|
||||
$[0] = second;
|
||||
$[1] = t1;
|
||||
$[2] = t2;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t2 = $[2];
|
||||
}
|
||||
useEffect(t1, t2);
|
||||
let t3;
|
||||
if ($[3] !== s) {
|
||||
t3 = <div>{s}</div>;
|
||||
$[3] = s;
|
||||
$[4] = t3;
|
||||
} else {
|
||||
t3 = $[4];
|
||||
}
|
||||
return t3;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented
|
||||
@@ -1,18 +0,0 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp
|
||||
|
||||
function Component({prop}) {
|
||||
const [s, setS] = useState();
|
||||
const [second, setSecond] = useState(prop);
|
||||
|
||||
/*
|
||||
* `second` is a source of state. It will inherit the value of `prop` in
|
||||
* the first render, but after that it will no longer be updated when
|
||||
* `prop` changes. So we shouldn't consider `second` as being derived from
|
||||
* `prop`
|
||||
*/
|
||||
useEffect(() => {
|
||||
setS(second);
|
||||
}, [second]);
|
||||
|
||||
return <div>{s}</div>;
|
||||
}
|
||||
Reference in New Issue
Block a user