Compare commits

..

1 Commits

Author SHA1 Message Date
Lauren Tan
880d203d5a [flow] Upgrade from 0.279 -> 0.280
Flow 0.280 introduced stricter type checking for `incompatible-type` errors,
requiring additional $FlowFixMe suppressions alongside existing ones. Changes:

- Made `QueuingStrategy` properties optional in streams.js
- Made all properties optional in Web Animations API types (EffectTiming,
  KeyframeAnimationOptions, etc.)
- Added `$FlowFixMe[incompatible-type]` alongside existing suppressions in
  multiple files where Flow now reports additional type mismatches
2025-12-08 16:19:30 -08:00
476 changed files with 6759 additions and 11586 deletions

View File

@@ -635,7 +635,6 @@ module.exports = {
FocusOptions: 'readonly',
OptionalEffectTiming: 'readonly',
__REACT_ROOT_PATH_TEST__: 'readonly',
spyOnDev: 'readonly',
spyOnDevAndProd: 'readonly',
spyOnProd: 'readonly',

View File

@@ -278,7 +278,6 @@ jobs:
if: steps.node_modules.outputs.cache-hit != 'true'
- run: yarn --cwd compiler install --frozen-lockfile
if: steps.node_modules.outputs.cache-hit != 'true'
- run: node --version
- run: yarn test ${{ matrix.params }} --ci --shard=${{ matrix.shard }}
# Hardcoded to improve parallelism
@@ -383,6 +382,9 @@ jobs:
-r=experimental --env=development,
-r=experimental --env=production,
# Dev Tools
--project=devtools -r=experimental,
# TODO: Update test config to support www build tests
# - "-r=www-classic --env=development --variant=false"
# - "-r=www-classic --env=production --variant=false"
@@ -446,54 +448,8 @@ jobs:
merge-multiple: true
- name: Display structure of build
run: ls -R build
- run: node --version
- run: yarn test --build ${{ matrix.test_params }} --shard=${{ matrix.shard }} --ci
test_build_devtools:
name: yarn test-build (devtools)
needs: [build_and_lint, runtime_node_modules_cache]
strategy:
fail-fast: false
matrix:
shard:
- 1/5
- 2/5
- 3/5
- 4/5
- 5/5
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }}
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: yarn
cache-dependency-path: yarn.lock
- name: Restore cached node_modules
uses: actions/cache/restore@v4
id: node_modules
with:
path: |
**/node_modules
key: runtime-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
# Don't use restore-keys here. Otherwise the cache grows indefinitely.
- name: Ensure clean build directory
run: rm -rf build
- run: yarn install --frozen-lockfile
if: steps.node_modules.outputs.cache-hit != 'true'
- name: Restore archived build
uses: actions/download-artifact@v4
with:
pattern: _build_*
path: build
merge-multiple: true
- name: Display structure of build
run: ls -R build
- run: node --version
- run: yarn test --build --project=devtools -r=experimental --shard=${{ matrix.shard }} --ci
process_artifacts_combined:
name: Process artifacts combined
needs: [build_and_lint, runtime_node_modules_cache]

View File

@@ -1,6 +1,9 @@
# react runtime
build
# flow-typed generated files use Flow syntax Prettier can't parse
flow-typed
packages/react-devtools-core/dist
packages/react-devtools-extensions/chrome/build
packages/react-devtools-extensions/firefox/build

View File

@@ -35,13 +35,13 @@
"lru-cache": "^11.2.2",
"lz-string": "^1.5.0",
"monaco-editor": "^0.52.0",
"next": "15.5.9",
"next": "15.5.7",
"notistack": "^3.0.0-alpha.7",
"prettier": "^3.3.3",
"pretty-format": "^29.3.1",
"re-resizable": "^6.9.16",
"react": "19.2.3",
"react-dom": "19.2.3"
"react": "19.2",
"react-dom": "19.2"
},
"devDependencies": {
"@types/node": "18.11.9",

View File

@@ -715,10 +715,10 @@
dependencies:
"@monaco-editor/loader" "^1.6.1"
"@next/env@15.5.9":
version "15.5.9"
resolved "https://registry.yarnpkg.com/@next/env/-/env-15.5.9.tgz#53c2c34dc17cd87b61f70c6cc211e303123b2ab8"
integrity sha512-4GlTZ+EJM7WaW2HEZcyU317tIQDjkQIyENDLxYJfSWlfqguN+dHkZgyQTV/7ykvobU7yEH5gKvreNrH4B6QgIg==
"@next/env@15.5.7":
version "15.5.7"
resolved "https://registry.yarnpkg.com/@next/env/-/env-15.5.7.tgz#4168db34ae3bc9fd9ad3b951d327f4cfc38d4362"
integrity sha512-4h6Y2NyEkIEN7Z8YxkA27pq6zTkS09bUSYC0xjd0NpwFxjnIKeZEeH591o5WECSmjpUhLn3H2QLJcDye3Uzcvg==
"@next/eslint-plugin-next@15.5.2":
version "15.5.2"
@@ -3204,12 +3204,12 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
next@15.5.9:
version "15.5.9"
resolved "https://registry.yarnpkg.com/next/-/next-15.5.9.tgz#1b80d05865cc27e710fb4dcfc6fd9e726ed12ad4"
integrity sha512-agNLK89seZEtC5zUHwtut0+tNrc0Xw4FT/Dg+B/VLEo9pAcS9rtTKpek3V6kVcVwsB2YlqMaHdfZL4eLEVYuCg==
next@15.5.7:
version "15.5.7"
resolved "https://registry.yarnpkg.com/next/-/next-15.5.7.tgz#4507700b2bbcaf2c9fb7a9ad25c0dac2ba4a9a75"
integrity sha512-+t2/0jIJ48kUpGKkdlhgkv+zPTEOoXyr60qXe68eB/pl3CMJaLeIGjzp5D6Oqt25hCBiBTt8wEeeAzfJvUKnPQ==
dependencies:
"@next/env" "15.5.9"
"@next/env" "15.5.7"
"@swc/helpers" "0.5.15"
caniuse-lite "^1.0.30001579"
postcss "8.4.31"
@@ -3582,10 +3582,10 @@ re-resizable@^6.9.16:
resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.10.0.tgz#d684a096ab438f1a93f59ad3a580a206b0ce31ee"
integrity sha512-hysSK0xmA5nz24HBVztlk4yCqCLCvS32E6ZpWxVKop9x3tqCa4yAj1++facrmkOf62JsJHjmjABdKxXofYioCw==
react-dom@19.2.3:
version "19.2.3"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.2.3.tgz#f0b61d7e5c4a86773889fcc1853af3ed5f215b17"
integrity sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==
react-dom@19.2:
version "19.2.0"
resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz#00ed1e959c365e9a9d48f8918377465466ec3af8"
integrity sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==
dependencies:
scheduler "^0.27.0"
@@ -3599,10 +3599,10 @@ react-is@^18.0.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
react@19.2.3:
version "19.2.3"
resolved "https://registry.yarnpkg.com/react/-/react-19.2.3.tgz#d83e5e8e7a258cf6b4fe28640515f99b87cd19b8"
integrity sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==
react@19.2:
version "19.2.0"
resolved "https://registry.npmjs.org/react/-/react-19.2.0.tgz#d33dd1721698f4376ae57a54098cb47fc75d93a5"
integrity sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==
read-cache@^1.0.0:
version "1.0.0"

View File

@@ -279,20 +279,17 @@ function runWithEnvironment(
validateNoSetStateInRender(hir).unwrap();
}
if (
env.config.validateNoDerivedComputationsInEffects_exp &&
env.outputMode === 'lint'
) {
if (env.config.validateNoDerivedComputationsInEffects_exp) {
env.logErrors(validateNoDerivedComputationsInEffects_exp(hir));
} else if (env.config.validateNoDerivedComputationsInEffects) {
validateNoDerivedComputationsInEffects(hir);
}
if (env.config.validateNoSetStateInEffects && env.outputMode === 'lint') {
if (env.config.validateNoSetStateInEffects) {
env.logErrors(validateNoSetStateInEffects(hir, env));
}
if (env.config.validateNoJSXInTryStatements && env.outputMode === 'lint') {
if (env.config.validateNoJSXInTryStatements) {
env.logErrors(validateNoJSXInTryStatement(hir));
}
@@ -323,11 +320,7 @@ function runWithEnvironment(
value: hir,
});
if (
env.enableValidations &&
env.config.validateStaticComponents &&
env.outputMode === 'lint'
) {
if (env.enableValidations && env.config.validateStaticComponents) {
env.logErrors(validateStaticComponents(hir));
}

View File

@@ -4026,7 +4026,6 @@ function lowerAssignment(
pattern: {
kind: 'ArrayPattern',
items,
loc: lvalue.node.loc ?? GeneratedSource,
},
},
value,
@@ -4204,7 +4203,6 @@ function lowerAssignment(
pattern: {
kind: 'ObjectPattern',
properties,
loc: lvalue.node.loc ?? GeneratedSource,
},
},
value,

View File

@@ -225,15 +225,8 @@ export const EnvironmentConfigSchema = z.object({
/**
* Validate that dependencies supplied to effect hooks are exhaustive.
* Can be:
* - 'off': No validation (default)
* - 'all': Validate and report both missing and extra dependencies
* - 'missing-only': Only report missing dependencies
* - 'extra-only': Only report extra/unnecessary dependencies
*/
validateExhaustiveEffectDependencies: z
.enum(['off', 'all', 'missing-only', 'extra-only'])
.default('off'),
validateExhaustiveEffectDependencies: z.boolean().default(false),
/**
* When this is true, rather than pruning existing manual memoization but ensuring or validating

View File

@@ -694,13 +694,11 @@ export type SpreadPattern = {
export type ArrayPattern = {
kind: 'ArrayPattern';
items: Array<Place | SpreadPattern | Hole>;
loc: SourceLocation;
};
export type ObjectPattern = {
kind: 'ObjectPattern';
properties: Array<ObjectProperty | SpreadPattern>;
loc: SourceLocation;
};
export type ObjectPropertyKey =

View File

@@ -515,7 +515,6 @@ function emitDestructureProps(
pattern: {
kind: 'ObjectPattern',
properties,
loc: GeneratedSource,
},
kind: InstructionKind.Let,
},

View File

@@ -702,7 +702,7 @@ function codegenReactiveScope(
outputComments.push(name.name);
if (!cx.hasDeclared(identifier)) {
statements.push(
t.variableDeclaration('let', [createVariableDeclarator(name, null)]),
t.variableDeclaration('let', [t.variableDeclarator(name)]),
);
}
cacheLoads.push({name, index, value: wrapCacheDep(cx, name)});
@@ -1387,7 +1387,7 @@ function codegenInstructionNullable(
suggestions: null,
});
return createVariableDeclaration(instr.loc, 'const', [
createVariableDeclarator(codegenLValue(cx, lvalue), value),
t.variableDeclarator(codegenLValue(cx, lvalue), value),
]);
}
case InstructionKind.Function: {
@@ -1451,7 +1451,7 @@ function codegenInstructionNullable(
suggestions: null,
});
return createVariableDeclaration(instr.loc, 'let', [
createVariableDeclarator(codegenLValue(cx, lvalue), value),
t.variableDeclarator(codegenLValue(cx, lvalue), value),
]);
}
case InstructionKind.Reassign: {
@@ -1691,9 +1691,6 @@ function withLoc<T extends (...args: Array<any>) => t.Node>(
};
}
const createIdentifier = withLoc(t.identifier);
const createArrayPattern = withLoc(t.arrayPattern);
const createObjectPattern = withLoc(t.objectPattern);
const createBinaryExpression = withLoc(t.binaryExpression);
const createExpressionStatement = withLoc(t.expressionStatement);
const _createLabelledStatement = withLoc(t.labeledStatement);
@@ -1725,31 +1722,6 @@ const createTryStatement = withLoc(t.tryStatement);
const createBreakStatement = withLoc(t.breakStatement);
const createContinueStatement = withLoc(t.continueStatement);
function createVariableDeclarator(
id: t.LVal,
init?: t.Expression | null,
): t.VariableDeclarator {
const node = t.variableDeclarator(id, init);
/*
* The variable declarator location is not preserved in HIR, however, we can use the
* start location of the id and the end location of the init to recreate the
* exact original variable declarator location.
*
* Or if init is null, we likely have a declaration without an initializer, so we can use the id.loc.end as the end location.
*/
if (id.loc && (init === null || init?.loc)) {
node.loc = {
start: id.loc.start,
end: init?.loc?.end ?? id.loc.end,
filename: id.loc.filename,
identifierName: undefined,
};
}
return node;
}
function createHookGuard(
guard: ExternalFunction,
context: ProgramContext,
@@ -1857,7 +1829,7 @@ function codegenInstruction(
);
} else {
return createVariableDeclaration(instr.loc, 'const', [
createVariableDeclarator(
t.variableDeclarator(
convertIdentifier(instr.lvalue.identifier),
expressionValue,
),
@@ -2784,7 +2756,7 @@ function codegenArrayPattern(
): t.ArrayPattern {
const hasHoles = !pattern.items.every(e => e.kind !== 'Hole');
if (hasHoles) {
const result = createArrayPattern(pattern.loc, []);
const result = t.arrayPattern([]);
/*
* Older versions of babel have a validation bug fixed by
* https://github.com/babel/babel/pull/10917
@@ -2805,8 +2777,7 @@ function codegenArrayPattern(
}
return result;
} else {
return createArrayPattern(
pattern.loc,
return t.arrayPattern(
pattern.items.map(item => {
if (item.kind === 'Hole') {
return null;
@@ -2826,8 +2797,7 @@ function codegenLValue(
return codegenArrayPattern(cx, pattern);
}
case 'ObjectPattern': {
return createObjectPattern(
pattern.loc,
return t.objectPattern(
pattern.properties.map(property => {
if (property.kind === 'ObjectProperty') {
const key = codegenObjectPropertyKey(cx, property.key);
@@ -2946,7 +2916,7 @@ function convertIdentifier(identifier: Identifier): t.Identifier {
suggestions: null,
},
);
return createIdentifier(identifier.loc, identifier.name.value);
return t.identifier(identifier.name.value);
}
function compareScopeDependency(

View File

@@ -141,7 +141,6 @@ export function validateExhaustiveDependencies(
reactive,
startMemo.depsLoc,
ErrorCategory.MemoDependencies,
'all',
);
if (diagnostic != null) {
error.pushDiagnostic(diagnostic);
@@ -160,7 +159,7 @@ export function validateExhaustiveDependencies(
onStartMemoize,
onFinishMemoize,
onEffect: (inferred, manual, manualMemoLoc) => {
if (env.config.validateExhaustiveEffectDependencies === 'off') {
if (env.config.validateExhaustiveEffectDependencies === false) {
return;
}
if (DEBUG) {
@@ -196,17 +195,12 @@ export function validateExhaustiveDependencies(
});
}
}
const effectReportMode =
typeof env.config.validateExhaustiveEffectDependencies === 'string'
? env.config.validateExhaustiveEffectDependencies
: 'all';
const diagnostic = validateDependencies(
Array.from(inferred),
manualDeps,
reactive,
manualMemoLoc,
ErrorCategory.EffectExhaustiveDependencies,
effectReportMode,
);
if (diagnostic != null) {
error.pushDiagnostic(diagnostic);
@@ -226,7 +220,6 @@ function validateDependencies(
category:
| ErrorCategory.MemoDependencies
| ErrorCategory.EffectExhaustiveDependencies,
exhaustiveDepsReportMode: 'all' | 'missing-only' | 'extra-only',
): CompilerDiagnostic | null {
// Sort dependencies by name and path, with shorter/non-optional paths first
inferred.sort((a, b) => {
@@ -377,20 +370,9 @@ function validateDependencies(
extra.push(dep);
}
// Filter based on report mode
const filteredMissing =
exhaustiveDepsReportMode === 'extra-only' ? [] : missing;
const filteredExtra =
exhaustiveDepsReportMode === 'missing-only' ? [] : extra;
if (filteredMissing.length !== 0 || filteredExtra.length !== 0) {
if (missing.length !== 0 || extra.length !== 0) {
let suggestion: CompilerSuggestion | null = null;
if (
manualMemoLoc != null &&
typeof manualMemoLoc !== 'symbol' &&
manualMemoLoc.start.index != null &&
manualMemoLoc.end.index != null
) {
if (manualMemoLoc != null && typeof manualMemoLoc !== 'symbol') {
suggestion = {
description: 'Update dependencies',
range: [manualMemoLoc.start.index, manualMemoLoc.end.index],
@@ -406,13 +388,8 @@ function validateDependencies(
.join(', ')}]`,
};
}
const diagnostic = createDiagnostic(
category,
filteredMissing,
filteredExtra,
suggestion,
);
for (const dep of filteredMissing) {
const diagnostic = createDiagnostic(category, missing, extra, suggestion);
for (const dep of missing) {
let reactiveStableValueHint = '';
if (isStableType(dep.identifier)) {
reactiveStableValueHint =
@@ -425,7 +402,7 @@ function validateDependencies(
loc: dep.loc,
});
}
for (const dep of filteredExtra) {
for (const dep of extra) {
if (dep.root.kind === 'Global') {
diagnostic.withDetails({
kind: 'error',

View File

@@ -27,11 +27,7 @@ import {Result} from '../Utils/Result';
/**
* Some common node types that are important for coverage tracking.
* Based on istanbul-lib-instrument + some other common nodes we expect to be present in the generated AST.
*
* Note: For VariableDeclaration, VariableDeclarator, and Identifier, we enforce stricter validation
* that requires both the source location AND node type to match in the generated AST. This ensures
* that variable declarations maintain their structural integrity through compilation.
* Based on istanbul-lib-instrument
*/
const IMPORTANT_INSTRUMENTED_TYPES = new Set([
'ArrowFunctionExpression',
@@ -58,14 +54,6 @@ const IMPORTANT_INSTRUMENTED_TYPES = new Set([
'LabeledStatement',
'ConditionalExpression',
'LogicalExpression',
/**
* Note: these aren't important for coverage tracking,
* but we still want to track them to ensure we aren't regressing them when
* we fix the source location tracking for other nodes.
*/
'VariableDeclaration',
'Identifier',
]);
/**
@@ -126,13 +114,10 @@ export function validateSourceLocations(
): Result<void, CompilerError> {
const errors = new CompilerError();
/*
* Step 1: Collect important locations from the original source
* Note: Multiple node types can share the same location (e.g. VariableDeclarator and Identifier)
*/
// Step 1: Collect important locations from the original source
const importantOriginalLocations = new Map<
string,
{loc: t.SourceLocation; nodeTypes: Set<string>}
{loc: t.SourceLocation; nodeType: string}
>();
func.traverse({
@@ -152,31 +137,20 @@ export function validateSourceLocations(
// Collect the location if it exists
if (node.loc) {
const key = locationKey(node.loc);
const existing = importantOriginalLocations.get(key);
if (existing) {
existing.nodeTypes.add(node.type);
} else {
importantOriginalLocations.set(key, {
loc: node.loc,
nodeTypes: new Set([node.type]),
});
}
importantOriginalLocations.set(key, {
loc: node.loc,
nodeType: node.type,
});
}
},
});
// Step 2: Collect all locations from the generated AST with their node types
const generatedLocations = new Map<string, Set<string>>();
// Step 2: Collect all locations from the generated AST
const generatedLocations = new Set<string>();
function collectGeneratedLocations(node: t.Node): void {
if (node.loc) {
const key = locationKey(node.loc);
const nodeTypes = generatedLocations.get(key);
if (nodeTypes) {
nodeTypes.add(node.type);
} else {
generatedLocations.set(key, new Set([node.type]));
}
generatedLocations.add(locationKey(node.loc));
}
// Use Babel's VISITOR_KEYS to traverse only actual node properties
@@ -209,86 +183,22 @@ export function validateSourceLocations(
collectGeneratedLocations(outlined.fn.body);
}
/*
* Step 3: Validate that all important locations are preserved
* For certain node types, also validate that the node type matches
*/
const strictNodeTypes = new Set([
'VariableDeclaration',
'VariableDeclarator',
'Identifier',
]);
const reportMissingLocation = (
loc: t.SourceLocation,
nodeType: string,
): void => {
errors.pushDiagnostic(
CompilerDiagnostic.create({
category: ErrorCategory.Todo,
reason: 'Important source location missing in generated code',
description:
`Source location for ${nodeType} is missing in the generated output. This can cause coverage instrumentation ` +
`to fail to track this code properly, resulting in inaccurate coverage reports.`,
}).withDetails({
kind: 'error',
loc,
message: null,
}),
);
};
const reportWrongNodeType = (
loc: t.SourceLocation,
expectedType: string,
actualTypes: Set<string>,
): void => {
errors.pushDiagnostic(
CompilerDiagnostic.create({
category: ErrorCategory.Todo,
reason:
'Important source location has wrong node type in generated code',
description:
`Source location for ${expectedType} exists in the generated output but with wrong node type(s): ${Array.from(actualTypes).join(', ')}. ` +
`This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports.`,
}).withDetails({
kind: 'error',
loc,
message: null,
}),
);
};
for (const [key, {loc, nodeTypes}] of importantOriginalLocations) {
const generatedNodeTypes = generatedLocations.get(key);
if (!generatedNodeTypes) {
// Location is completely missing
reportMissingLocation(loc, Array.from(nodeTypes).join(', '));
} else {
// Location exists, check each node type
for (const nodeType of nodeTypes) {
if (
strictNodeTypes.has(nodeType) &&
!generatedNodeTypes.has(nodeType)
) {
/*
* For strict node types, the specific node type must be present
* Check if any generated node type is also an important original node type
*/
const hasValidNodeType = Array.from(generatedNodeTypes).some(
genType => nodeTypes.has(genType),
);
if (hasValidNodeType) {
// At least one generated node type is valid (also in original), so this is just missing
reportMissingLocation(loc, nodeType);
} else {
// None of the generated node types are in original - this is wrong node type
reportWrongNodeType(loc, nodeType, generatedNodeTypes);
}
}
}
// Step 3: Validate that all important locations are preserved
for (const [key, {loc, nodeType}] of importantOriginalLocations) {
if (!generatedLocations.has(key)) {
errors.pushDiagnostic(
CompilerDiagnostic.create({
category: ErrorCategory.Todo,
reason: 'Important source location missing in generated code',
description:
`Source location for ${nodeType} is missing in the generated output. This can cause coverage instrumentation ` +
`to fail to track this code properly, resulting in inaccurate coverage reports.`,
}).withDetails({
kind: 'error',
loc,
message: null,
}),
);
}
}

View File

@@ -35,8 +35,10 @@ function Component() {
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
const a = makeObject_Primitives();
const x = [];
x.push(a);
mutate(x);
t0 = [x, a];
$[0] = t0;

View File

@@ -33,6 +33,7 @@ function Component() {
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
const x = [];
x.push(a);
t1 = [x, a];
$[1] = t1;
} else {

View File

@@ -85,10 +85,14 @@ function Component(t0) {
let t1;
if ($[0] !== prop) {
const obj = shallowCopy(prop);
const aliasedObj = identity(obj);
const getId = () => obj.id;
mutate(aliasedObj);
setPropertyByKey(aliasedObj, "id", prop.id + 1);
t1 = <Stringify getId={getId} shouldInvokeFns={true} />;
$[0] = prop;
$[1] = t1;

View File

@@ -181,9 +181,12 @@ function Component(t0) {
if ($[0] !== prop) {
const obj = shallowCopy(prop);
const aliasedObj = identity(obj);
const id = [obj.id];
mutate(aliasedObj);
setPropertyByKey(aliasedObj, "id", prop.id + 1);
t1 = <Stringify id={id} />;
$[0] = prop;
$[1] = t1;

View File

@@ -54,6 +54,7 @@ function Foo(t0) {
let t1;
if ($[0] !== cond1 || $[1] !== cond2) {
const arr = makeArray({ a: 2 }, 2, []);
t1 = cond1 ? (
<>
<div>{identity("foo")}</div>

View File

@@ -49,6 +49,7 @@ function Component() {
ref.current = "";
}
};
t0 = () => {
setRef();
};

View File

@@ -49,6 +49,7 @@ function Component() {
ref.current.value = "";
}
};
t0 = () => {
setRef();
};

View File

@@ -74,6 +74,7 @@ function Component() {
console.log(ref.current.value);
}
};
t0 = (
<>
<input ref={ref} />

View File

@@ -36,6 +36,7 @@ function useArrayOfRef() {
const callback = (value) => {
ref.current = value;
};
t0 = [callback];
$[0] = t0;
} else {

View File

@@ -35,6 +35,7 @@ function Component(props) {
const arr = [...bar(props)];
return arr.at(x);
};
t1 = fn();
$[2] = props;
$[3] = x;

View File

@@ -61,6 +61,7 @@ function useBar(t0) {
if ($[0] !== arg) {
const s = new Set([1, 5, 4]);
const mutableIterator = s.values();
t1 = [arg, ...mutableIterator];
$[0] = arg;
$[1] = t1;

View File

@@ -28,6 +28,7 @@ function Component(props) {
const a = [];
const b = {};
foo(a, b);
foo(b);
t0 = <div a={a} b={b} />;
$[0] = t0;

View File

@@ -45,6 +45,7 @@ function useKeyCommand() {
const nextPosition = direction === "left" ? addOne(position) : position;
currentPosition.current = nextPosition;
};
const moveLeft = { handler: handleKey("left") };
const moveRight = { handler: handleKey("right") };
t0 = [moveLeft, moveRight];

View File

@@ -45,6 +45,7 @@ function Component(t0) {
z.a = 2;
mutate(y.b);
};
x();
t1 = [y, z];
$[0] = a;

View File

@@ -29,6 +29,7 @@ function MyComponentName(props) {
const x = {};
foo(x, props.a);
foo(x, props.b);
y = [];
y.push(x);
$[0] = props.a;

View File

@@ -34,6 +34,7 @@ function useTest() {
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
let w = {};
const t1 = (w = 42);
const t2 = w;

View File

@@ -34,6 +34,7 @@ function useTest() {
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
const w = {};
const t1 = (w.x = 42);
const t2 = w.x;

View File

@@ -44,9 +44,11 @@ function ComponentA(props) {
if (b) {
a.push(props.p0);
}
if (props.p1) {
b.push(props.p2);
}
t0 = <Foo a={a} b={b} />;
$[0] = props.p0;
$[1] = props.p1;
@@ -67,9 +69,11 @@ function ComponentB(props) {
if (mayMutate(b)) {
a.push(props.p0);
}
if (props.p1) {
b.push(props.p2);
}
t0 = <Foo a={a} b={b} />;
$[0] = props.p0;
$[1] = props.p1;

View File

@@ -28,6 +28,7 @@ function Component(props) {
const a = [];
const b = {};
new Foo(a, b);
new Foo(b);
t0 = <div a={a} b={b} />;
$[0] = t0;

View File

@@ -34,6 +34,7 @@ function Component(props) {
const callback = () => {
console.log(x);
};
x = {};
t0 = <Stringify callback={callback} shouldInvokeFns={true} />;
$[0] = t0;

View File

@@ -75,6 +75,7 @@ function Component(props) {
let t0;
if ($[0] !== post) {
const allUrls = [];
const { media: t1, comments: t2, urls: t3 } = post;
const media = t1 === undefined ? null : t1;
let t4;
@@ -101,6 +102,7 @@ function Component(props) {
if (!comments.length) {
return;
}
console.log(comments.length);
};
$[6] = comments.length;
@@ -109,6 +111,7 @@ function Component(props) {
t6 = $[7];
}
const onClick = t6;
allUrls.push(...urls);
t0 = <Stringify media={media} allUrls={allUrls} onClick={onClick} />;
$[0] = post;

View File

@@ -53,6 +53,7 @@ function Component(props) {
let t0;
if ($[0] !== post) {
const allUrls = [];
const { media, comments, urls } = post;
let t1;
if ($[2] !== comments.length) {
@@ -60,6 +61,7 @@ function Component(props) {
if (!comments.length) {
return;
}
console.log(comments.length);
};
$[2] = comments.length;
@@ -68,6 +70,7 @@ function Component(props) {
t1 = $[3];
}
const onClick = t1;
allUrls.push(...urls);
t0 = <Media media={media} onClick={onClick} />;
$[0] = post;

View File

@@ -57,6 +57,7 @@ function Component(t0) {
let y;
if ($[0] !== a || $[1] !== b || $[2] !== c) {
x = [];
if (a) {
let t1;
if ($[5] !== b) {

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
function Component({value, enabled}) {
@@ -29,21 +29,43 @@ export const FIXTURE_ENTRYPOINT = {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import { useEffect, useState } from "react";
function Component({ value, enabled }) {
function Component(t0) {
const $ = _c(6);
const { value, enabled } = t0;
const [localValue, setLocalValue] = useState("");
let t1;
let t2;
if ($[0] !== enabled || $[1] !== value) {
t1 = () => {
if (enabled) {
setLocalValue(value);
} else {
setLocalValue("disabled");
}
};
useEffect(() => {
if (enabled) {
setLocalValue(value);
} else {
setLocalValue("disabled");
}
}, [value, enabled]);
return <div>{localValue}</div>;
t2 = [value, enabled];
$[0] = enabled;
$[1] = value;
$[2] = t1;
$[3] = t2;
} else {
t1 = $[2];
t2 = $[3];
}
useEffect(t1, t2);
let t3;
if ($[4] !== localValue) {
t3 = <div>{localValue}</div>;
$[4] = localValue;
$[5] = t3;
} else {
t3 = $[5];
}
return t3;
}
export const FIXTURE_ENTRYPOINT = {
@@ -56,8 +78,8 @@ export const FIXTURE_ENTRYPOINT = {
## Logs
```
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [value]\n\nData Flow Tree:\n└── value (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":9,"column":6,"index":263},"end":{"line":9,"column":19,"index":276},"filename":"derived-state-conditionally-in-effect.ts","identifierName":"setLocalValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":16,"column":1,"index":397},"filename":"derived-state-conditionally-in-effect.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [value]\n\nData Flow Tree:\n└── value (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":9,"column":6,"index":244},"end":{"line":9,"column":19,"index":257},"filename":"derived-state-conditionally-in-effect.ts","identifierName":"setLocalValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":16,"column":1,"index":378},"filename":"derived-state-conditionally-in-effect.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
```
### Eval output

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
function Component({value, enabled}) {

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
export default function Component({input = 'empty'}) {
@@ -26,18 +26,38 @@ export const FIXTURE_ENTRYPOINT = {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import { useEffect, useState } from "react";
export default function Component({ input = "empty" }) {
export default function Component(t0) {
const $ = _c(5);
const { input: t1 } = t0;
const input = t1 === undefined ? "empty" : t1;
const [currInput, setCurrInput] = useState(input);
const localConst = "local const";
useEffect(() => {
setCurrInput(input + localConst);
}, [input, localConst]);
return <div>{currInput}</div>;
let t2;
let t3;
if ($[0] !== input) {
t2 = () => {
setCurrInput(input + "local const");
};
t3 = [input, "local const"];
$[0] = input;
$[1] = t2;
$[2] = t3;
} else {
t2 = $[1];
t3 = $[2];
}
useEffect(t2, t3);
let t4;
if ($[3] !== currInput) {
t4 = <div>{currInput}</div>;
$[3] = currInput;
$[4] = t4;
} else {
t4 = $[4];
}
return t4;
}
export const FIXTURE_ENTRYPOINT = {
@@ -50,8 +70,8 @@ export const FIXTURE_ENTRYPOINT = {
## Logs
```
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [input]\n\nData Flow Tree:\n└── input (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":9,"column":4,"index":295},"end":{"line":9,"column":16,"index":307},"filename":"derived-state-from-default-props.ts","identifierName":"setCurrInput"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":141},"end":{"line":13,"column":1,"index":391},"filename":"derived-state-from-default-props.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [input]\n\nData Flow Tree:\n└── input (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":9,"column":4,"index":276},"end":{"line":9,"column":16,"index":288},"filename":"derived-state-from-default-props.ts","identifierName":"setCurrInput"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":122},"end":{"line":13,"column":1,"index":372},"filename":"derived-state-from-default-props.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
```
### Eval output

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
export default function Component({input = 'empty'}) {

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
@@ -23,20 +23,45 @@ function Component({shouldChange}) {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import { useEffect, useState } from "react";
function Component({ shouldChange }) {
function Component(t0) {
const $ = _c(7);
const { shouldChange } = t0;
const [count, setCount] = useState(0);
useEffect(() => {
if (shouldChange) {
setCount(count + 1);
}
}, [count]);
return <div>{count}</div>;
let t1;
if ($[0] !== count || $[1] !== shouldChange) {
t1 = () => {
if (shouldChange) {
setCount(count + 1);
}
};
$[0] = count;
$[1] = shouldChange;
$[2] = t1;
} else {
t1 = $[2];
}
let t2;
if ($[3] !== count) {
t2 = [count];
$[3] = count;
$[4] = t2;
} else {
t2 = $[4];
}
useEffect(t1, t2);
let t3;
if ($[5] !== count) {
t3 = <div>{count}</div>;
$[5] = count;
$[6] = t3;
} else {
t3 = $[6];
}
return t3;
}
```
@@ -44,8 +69,8 @@ function Component({ shouldChange }) {
## Logs
```
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nState: [count]\n\nData Flow Tree:\n└── count (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":10,"column":6,"index":256},"end":{"line":10,"column":14,"index":264},"filename":"derived-state-from-local-state-in-effect.ts","identifierName":"setCount"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":127},"end":{"line":15,"column":1,"index":329},"filename":"derived-state-from-local-state-in-effect.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":3,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nState: [count]\n\nData Flow Tree:\n└── count (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":10,"column":6,"index":237},"end":{"line":10,"column":14,"index":245},"filename":"derived-state-from-local-state-in-effect.ts","identifierName":"setCount"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":108},"end":{"line":15,"column":1,"index":310},"filename":"derived-state-from-local-state-in-effect.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":3,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
```
### Eval output

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
function Component({firstName}) {
@@ -33,25 +33,68 @@ export const FIXTURE_ENTRYPOINT = {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import { useEffect, useState } from "react";
function Component({ firstName }) {
function Component(t0) {
const $ = _c(12);
const { firstName } = t0;
const [lastName, setLastName] = useState("Doe");
const [fullName, setFullName] = useState("John");
const middleName = "D.";
useEffect(() => {
setFullName(firstName + " " + middleName + " " + lastName);
}, [firstName, middleName, lastName]);
return (
<div>
<input value={lastName} onChange={(e) => setLastName(e.target.value)} />
<div>{fullName}</div>
</div>
);
let t1;
let t2;
if ($[0] !== firstName || $[1] !== lastName) {
t1 = () => {
setFullName(firstName + " " + "D." + " " + lastName);
};
t2 = [firstName, "D.", lastName];
$[0] = firstName;
$[1] = lastName;
$[2] = t1;
$[3] = t2;
} else {
t1 = $[2];
t2 = $[3];
}
useEffect(t1, t2);
let t3;
if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
t3 = (e) => setLastName(e.target.value);
$[4] = t3;
} else {
t3 = $[4];
}
let t4;
if ($[5] !== lastName) {
t4 = <input value={lastName} onChange={t3} />;
$[5] = lastName;
$[6] = t4;
} else {
t4 = $[6];
}
let t5;
if ($[7] !== fullName) {
t5 = <div>{fullName}</div>;
$[7] = fullName;
$[8] = t5;
} else {
t5 = $[8];
}
let t6;
if ($[9] !== t4 || $[10] !== t5) {
t6 = (
<div>
{t4}
{t5}
</div>
);
$[9] = t4;
$[10] = t5;
$[11] = t6;
} else {
t6 = $[11];
}
return t6;
}
export const FIXTURE_ENTRYPOINT = {
@@ -64,8 +107,8 @@ export const FIXTURE_ENTRYPOINT = {
## Logs
```
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [firstName]\nState: [lastName]\n\nData Flow Tree:\n├── firstName (Prop)\n└── lastName (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":11,"column":4,"index":316},"end":{"line":11,"column":15,"index":327},"filename":"derived-state-from-prop-local-state-and-component-scope.ts","identifierName":"setFullName"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":20,"column":1,"index":561},"filename":"derived-state-from-prop-local-state-and-component-scope.ts"},"fnName":"Component","memoSlots":12,"memoBlocks":5,"memoValues":6,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [firstName]\nState: [lastName]\n\nData Flow Tree:\n├── firstName (Prop)\n└── lastName (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":11,"column":4,"index":297},"end":{"line":11,"column":15,"index":308},"filename":"derived-state-from-prop-local-state-and-component-scope.ts","identifierName":"setFullName"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":20,"column":1,"index":542},"filename":"derived-state-from-prop-local-state-and-component-scope.ts"},"fnName":"Component","memoSlots":12,"memoBlocks":5,"memoValues":6,"prunedMemoBlocks":0,"prunedMemoValues":0}
```
### Eval output

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
function Component({firstName}) {

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
function Component({initialName}) {
@@ -29,21 +29,48 @@ export const FIXTURE_ENTRYPOINT = {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import { useEffect, useState } from "react";
function Component({ initialName }) {
function Component(t0) {
const $ = _c(6);
const { initialName } = t0;
const [name, setName] = useState("");
useEffect(() => {
setName(initialName);
}, [initialName]);
return (
<div>
<input value={name} onChange={(e) => setName(e.target.value)} />
</div>
);
let t1;
let t2;
if ($[0] !== initialName) {
t1 = () => {
setName(initialName);
};
t2 = [initialName];
$[0] = initialName;
$[1] = t1;
$[2] = t2;
} else {
t1 = $[1];
t2 = $[2];
}
useEffect(t1, t2);
let t3;
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
t3 = (e) => setName(e.target.value);
$[3] = t3;
} else {
t3 = $[3];
}
let t4;
if ($[4] !== name) {
t4 = (
<div>
<input value={name} onChange={t3} />
</div>
);
$[4] = name;
$[5] = t4;
} else {
t4 = $[5];
}
return t4;
}
export const FIXTURE_ENTRYPOINT = {
@@ -56,7 +83,7 @@ export const FIXTURE_ENTRYPOINT = {
## Logs
```
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":16,"column":1,"index":378},"filename":"derived-state-from-prop-setter-call-outside-effect-no-error.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":3,"memoValues":4,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":16,"column":1,"index":359},"filename":"derived-state-from-prop-setter-call-outside-effect-no-error.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":3,"memoValues":4,"prunedMemoBlocks":0,"prunedMemoValues":0}
```
### Eval output

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
function Component({initialName}) {

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp
function Component({value}) {
const [checked, setChecked] = useState('');
@@ -19,16 +19,36 @@ function Component({value}) {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp
function Component({ value }) {
function Component(t0) {
const $ = _c(5);
const { value } = t0;
const [checked, setChecked] = useState("");
useEffect(() => {
setChecked(value === "" ? [] : value.split(","));
}, [value]);
return <div>{checked}</div>;
let t1;
let t2;
if ($[0] !== value) {
t1 = () => {
setChecked(value === "" ? [] : value.split(","));
};
t2 = [value];
$[0] = value;
$[1] = t1;
$[2] = t2;
} else {
t1 = $[1];
t2 = $[2];
}
useEffect(t1, t2);
let t3;
if ($[3] !== checked) {
t3 = <div>{checked}</div>;
$[3] = checked;
$[4] = t3;
} else {
t3 = $[4];
}
return t3;
}
```

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp
function Component({value}) {
const [checked, setChecked] = useState('');

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
function MockComponent({onSet}) {
@@ -28,20 +28,50 @@ export const FIXTURE_ENTRYPOINT = {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import { useEffect, useState } from "react";
function MockComponent({ onSet }) {
return <div onClick={() => onSet("clicked")}>Mock Component</div>;
function MockComponent(t0) {
const $ = _c(2);
const { onSet } = t0;
let t1;
if ($[0] !== onSet) {
t1 = <div onClick={() => onSet("clicked")}>Mock Component</div>;
$[0] = onSet;
$[1] = t1;
} else {
t1 = $[1];
}
return t1;
}
function Component({ propValue }) {
const [value, setValue] = useState(null);
useEffect(() => {
setValue(propValue);
}, [propValue]);
return <MockComponent onSet={setValue} />;
function Component(t0) {
const $ = _c(4);
const { propValue } = t0;
const [, setValue] = useState(null);
let t1;
let t2;
if ($[0] !== propValue) {
t1 = () => {
setValue(propValue);
};
t2 = [propValue];
$[0] = propValue;
$[1] = t1;
$[2] = t2;
} else {
t1 = $[1];
t2 = $[2];
}
useEffect(t1, t2);
let t3;
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
t3 = <MockComponent onSet={setValue} />;
$[3] = t3;
} else {
t3 = $[3];
}
return t3;
}
export const FIXTURE_ENTRYPOINT = {
@@ -54,8 +84,8 @@ export const FIXTURE_ENTRYPOINT = {
## Logs
```
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":6,"column":1,"index":230},"filename":"derived-state-from-prop-setter-used-outside-effect-no-error.ts"},"fnName":"MockComponent","memoSlots":2,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":8,"column":0,"index":232},"end":{"line":15,"column":1,"index":421},"filename":"derived-state-from-prop-setter-used-outside-effect-no-error.ts"},"fnName":"Component","memoSlots":4,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":6,"column":1,"index":211},"filename":"derived-state-from-prop-setter-used-outside-effect-no-error.ts"},"fnName":"MockComponent","memoSlots":2,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":8,"column":0,"index":213},"end":{"line":15,"column":1,"index":402},"filename":"derived-state-from-prop-setter-used-outside-effect-no-error.ts"},"fnName":"Component","memoSlots":4,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
```
### Eval output

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
function MockComponent({onSet}) {

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
function Component({value}) {
@@ -26,18 +26,38 @@ export const FIXTURE_ENTRYPOINT = {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import { useEffect, useState } from "react";
function Component({ value }) {
function Component(t0) {
const $ = _c(5);
const { value } = t0;
const [localValue, setLocalValue] = useState("");
useEffect(() => {
setLocalValue(value);
document.title = `Value: ${value}`;
}, [value]);
return <div>{localValue}</div>;
let t1;
let t2;
if ($[0] !== value) {
t1 = () => {
setLocalValue(value);
document.title = `Value: ${value}`;
};
t2 = [value];
$[0] = value;
$[1] = t1;
$[2] = t2;
} else {
t1 = $[1];
t2 = $[2];
}
useEffect(t1, t2);
let t3;
if ($[3] !== localValue) {
t3 = <div>{localValue}</div>;
$[3] = localValue;
$[4] = t3;
} else {
t3 = $[4];
}
return t3;
}
export const FIXTURE_ENTRYPOINT = {
@@ -50,8 +70,8 @@ export const FIXTURE_ENTRYPOINT = {
## Logs
```
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [value]\n\nData Flow Tree:\n└── value (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":8,"column":4,"index":233},"end":{"line":8,"column":17,"index":246},"filename":"derived-state-from-prop-with-side-effect.ts","identifierName":"setLocalValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":13,"column":1,"index":346},"filename":"derived-state-from-prop-with-side-effect.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [value]\n\nData Flow Tree:\n└── value (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":8,"column":4,"index":214},"end":{"line":8,"column":17,"index":227},"filename":"derived-state-from-prop-with-side-effect.ts","identifierName":"setLocalValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":13,"column":1,"index":327},"filename":"derived-state-from-prop-with-side-effect.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
```
### Eval output

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
function Component({value}) {

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState, useRef} from 'react';
export default function Component({test}) {
@@ -27,19 +27,39 @@ export const FIXTURE_ENTRYPOINT = {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import { useEffect, useState, useRef } from "react";
export default function Component({ test }) {
export default function Component(t0) {
const $ = _c(5);
const { test } = t0;
const [local, setLocal] = useState("");
const myRef = useRef(null);
useEffect(() => {
setLocal(myRef.current + test);
}, [test]);
return <>{local}</>;
let t1;
let t2;
if ($[0] !== test) {
t1 = () => {
setLocal(myRef.current + test);
};
t2 = [test];
$[0] = test;
$[1] = t1;
$[2] = t2;
} else {
t1 = $[1];
t2 = $[2];
}
useEffect(t1, t2);
let t3;
if ($[3] !== local) {
t3 = <>{local}</>;
$[3] = local;
$[4] = t3;
} else {
t3 = $[4];
}
return t3;
}
export const FIXTURE_ENTRYPOINT = {
@@ -52,7 +72,7 @@ export const FIXTURE_ENTRYPOINT = {
## Logs
```
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":149},"end":{"line":14,"column":1,"index":347},"filename":"derived-state-from-ref-and-state-no-error.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":130},"end":{"line":14,"column":1,"index":328},"filename":"derived-state-from-ref-and-state-no-error.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
```
### Eval output

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState, useRef} from 'react';
export default function Component({test}) {

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
function Component({propValue}) {
@@ -30,22 +30,48 @@ export const FIXTURE_ENTRYPOINT = {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import { useEffect, useState } from "react";
function Component({ propValue }) {
function Component(t0) {
const $ = _c(6);
const { propValue } = t0;
const [value, setValue] = useState(null);
function localFunction() {
console.log("local function");
let t1;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t1 = function localFunction() {
console.log("local function");
};
$[0] = t1;
} else {
t1 = $[0];
}
useEffect(() => {
setValue(propValue);
localFunction();
}, [propValue]);
return <div>{value}</div>;
const localFunction = t1;
let t2;
let t3;
if ($[1] !== propValue) {
t2 = () => {
setValue(propValue);
localFunction();
};
t3 = [propValue];
$[1] = propValue;
$[2] = t2;
$[3] = t3;
} else {
t2 = $[2];
t3 = $[3];
}
useEffect(t2, t3);
let t4;
if ($[4] !== value) {
t4 = <div>{value}</div>;
$[4] = value;
$[5] = t4;
} else {
t4 = $[5];
}
return t4;
}
export const FIXTURE_ENTRYPOINT = {
@@ -58,8 +84,8 @@ export const FIXTURE_ENTRYPOINT = {
## Logs
```
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [propValue]\n\nData Flow Tree:\n└── propValue (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":12,"column":4,"index":298},"end":{"line":12,"column":12,"index":306},"filename":"effect-contains-local-function-call.ts","identifierName":"setValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":17,"column":1,"index":390},"filename":"effect-contains-local-function-call.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":3,"memoValues":4,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [propValue]\n\nData Flow Tree:\n└── propValue (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":12,"column":4,"index":279},"end":{"line":12,"column":12,"index":287},"filename":"effect-contains-local-function-call.ts","identifierName":"setValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":17,"column":1,"index":371},"filename":"effect-contains-local-function-call.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":3,"memoValues":4,"prunedMemoBlocks":0,"prunedMemoValues":0}
```
### Eval output

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
function Component({propValue}) {

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
function Component({propValue, onChange}) {
@@ -25,17 +25,43 @@ export const FIXTURE_ENTRYPOINT = {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import { useEffect, useState } from "react";
function Component({ propValue, onChange }) {
function Component(t0) {
const $ = _c(7);
const { propValue, onChange } = t0;
const [value, setValue] = useState(null);
useEffect(() => {
setValue(propValue);
onChange();
}, [propValue]);
return <div>{value}</div>;
let t1;
if ($[0] !== onChange || $[1] !== propValue) {
t1 = () => {
setValue(propValue);
onChange();
};
$[0] = onChange;
$[1] = propValue;
$[2] = t1;
} else {
t1 = $[2];
}
let t2;
if ($[3] !== propValue) {
t2 = [propValue];
$[3] = propValue;
$[4] = t2;
} else {
t2 = $[4];
}
useEffect(t1, t2);
let t3;
if ($[5] !== value) {
t3 = <div>{value}</div>;
$[5] = value;
$[6] = t3;
} else {
t3 = $[6];
}
return t3;
}
export const FIXTURE_ENTRYPOINT = {
@@ -48,8 +74,8 @@ export const FIXTURE_ENTRYPOINT = {
## Logs
```
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":12,"column":1,"index":325},"filename":"effect-contains-prop-function-call-no-error.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":3,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":16,"column":41,"index":421},"end":{"line":16,"column":49,"index":429},"filename":"effect-contains-prop-function-call-no-error.ts"},"fnName":null,"memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":12,"column":1,"index":306},"filename":"effect-contains-prop-function-call-no-error.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":3,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":16,"column":41,"index":402},"end":{"line":16,"column":49,"index":410},"filename":"effect-contains-prop-function-call-no-error.ts"},"fnName":null,"memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
```
### Eval output

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
function Component({propValue, onChange}) {

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
function Component({prop}) {
const [s, setS] = useState(0);
@@ -18,15 +18,36 @@ function Component({prop}) {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
function Component({ prop }) {
const [s, setS] = useState(0);
useEffect(() => {
setS(prop);
}, [prop, setS]);
return <div>{prop}</div>;
function Component(t0) {
const $ = _c(5);
const { prop } = t0;
const [, setS] = useState(0);
let t1;
let t2;
if ($[0] !== prop) {
t1 = () => {
setS(prop);
};
t2 = [prop, setS];
$[0] = prop;
$[1] = t1;
$[2] = t2;
} else {
t1 = $[1];
t2 = $[2];
}
useEffect(t1, t2);
let t3;
if ($[3] !== prop) {
t3 = <div>{prop}</div>;
$[3] = prop;
$[4] = t3;
} else {
t3 = $[4];
}
return t3;
}
```
@@ -34,8 +55,8 @@ function Component({ prop }) {
## Logs
```
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [prop]\n\nData Flow Tree:\n└── prop (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":6,"column":4,"index":169},"end":{"line":6,"column":8,"index":173},"filename":"effect-used-in-dep-array-still-errors.ts","identifierName":"setS"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":83},"end":{"line":10,"column":1,"index":231},"filename":"effect-used-in-dep-array-still-errors.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [prop]\n\nData Flow Tree:\n└── prop (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":6,"column":4,"index":150},"end":{"line":6,"column":8,"index":154},"filename":"effect-used-in-dep-array-still-errors.ts","identifierName":"setS"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":64},"end":{"line":10,"column":1,"index":212},"filename":"effect-used-in-dep-array-still-errors.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
```
### Eval output

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
function Component({prop}) {
const [s, setS] = useState(0);

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
@@ -29,26 +29,39 @@ function Component(file: File) {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import { useEffect, useState } from "react";
function Component(file: File) {
function Component(file) {
const $ = _c(5);
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} />;
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;
}
```
@@ -56,7 +69,7 @@ function Component(file: File) {
## Logs
```
{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":127},"end":{"line":21,"column":1,"index":719},"filename":"effect-with-cleanup-function-depending-on-derived-computation-value.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"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

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
function Component({propValue}) {
@@ -25,17 +25,38 @@ export const FIXTURE_ENTRYPOINT = {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import { useEffect, useState } from "react";
function Component({ propValue }) {
function Component(t0) {
const $ = _c(5);
const { propValue } = t0;
const [value, setValue] = useState(null);
useEffect(() => {
setValue(propValue);
globalCall();
}, [propValue]);
return <div>{value}</div>;
let t1;
let t2;
if ($[0] !== propValue) {
t1 = () => {
setValue(propValue);
globalCall();
};
t2 = [propValue];
$[0] = propValue;
$[1] = t1;
$[2] = t2;
} else {
t1 = $[1];
t2 = $[2];
}
useEffect(t1, t2);
let t3;
if ($[3] !== value) {
t3 = <div>{value}</div>;
$[3] = value;
$[4] = t3;
} else {
t3 = $[4];
}
return t3;
}
export const FIXTURE_ENTRYPOINT = {
@@ -48,7 +69,7 @@ export const FIXTURE_ENTRYPOINT = {
## Logs
```
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":12,"column":1,"index":317},"filename":"effect-with-global-function-call-no-error.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":12,"column":1,"index":298},"filename":"effect-with-global-function-call-no-error.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
```
### Eval output

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
function Component({propValue}) {

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly
function Component({setParentState, prop}) {
useEffect(() => {
@@ -17,14 +17,40 @@ function Component({setParentState, prop}) {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly
function Component({ setParentState, prop }) {
useEffect(() => {
setParentState(prop);
}, [prop]);
return <div>{prop}</div>;
function Component(t0) {
const $ = _c(7);
const { setParentState, prop } = t0;
let t1;
if ($[0] !== prop || $[1] !== setParentState) {
t1 = () => {
setParentState(prop);
};
$[0] = prop;
$[1] = setParentState;
$[2] = t1;
} else {
t1 = $[2];
}
let t2;
if ($[3] !== prop) {
t2 = [prop];
$[3] = prop;
$[4] = t2;
} else {
t2 = $[4];
}
useEffect(t1, t2);
let t3;
if ($[5] !== prop) {
t3 = <div>{prop}</div>;
$[5] = prop;
$[6] = t3;
} else {
t3 = $[6];
}
return t3;
}
```
@@ -32,7 +58,7 @@ function Component({ setParentState, prop }) {
## Logs
```
{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":124},"end":{"line":9,"column":1,"index":259},"filename":"from-props-setstate-in-effect-no-error.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":3,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":105},"end":{"line":9,"column":1,"index":240},"filename":"from-props-setstate-in-effect-no-error.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":3,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
```
### Eval output

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly
function Component({setParentState, prop}) {
useEffect(() => {

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
function Component() {
const [foo, setFoo] = useState({});
@@ -40,37 +40,66 @@ function Component() {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
function Component() {
const [foo, setFoo] = useState({});
const [bar, setBar] = useState(new Set());
const $ = _c(9);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = {};
$[0] = t0;
} else {
t0 = $[0];
}
const [foo, setFoo] = useState(t0);
let t1;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
t1 = new Set();
$[1] = t1;
} else {
t1 = $[1];
}
const [bar] = useState(t1);
let t2;
let t3;
if ($[2] !== bar || $[3] !== foo) {
t2 = () => {
let isChanged = false;
/*
* isChanged is considered context of the effect's function expression,
* if we don't bail out of effect mutation derivation tracking, isChanged
* will inherit the sources of the effect's function expression.
*
* This is innacurate and with the multiple passes ends up causing an infinite loop.
*/
useEffect(() => {
let isChanged = false;
const newData = foo.map((val) => {
bar.someMethod(val);
isChanged = true;
});
const newData = foo.map((val) => {
bar.someMethod(val);
isChanged = true;
});
if (isChanged) {
setFoo(newData);
}
};
if (isChanged) {
setFoo(newData);
}
}, [foo, bar]);
return (
<div>
{foo}, {bar}
</div>
);
t3 = [foo, bar];
$[2] = bar;
$[3] = foo;
$[4] = t2;
$[5] = t3;
} else {
t2 = $[4];
t3 = $[5];
}
useEffect(t2, t3);
let t4;
if ($[6] !== bar || $[7] !== foo) {
t4 = (
<div>
{foo}, {bar}
</div>
);
$[6] = bar;
$[7] = foo;
$[8] = t4;
} else {
t4 = $[8];
}
return t4;
}
```
@@ -78,8 +107,8 @@ function Component() {
## Logs
```
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nState: [foo, bar]\n\nData Flow Tree:\n└── newData\n ├── foo (State)\n └── bar (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":23,"column":6,"index":682},"end":{"line":23,"column":12,"index":688},"filename":"function-expression-mutation-edge-case.ts","identifierName":"setFoo"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":83},"end":{"line":32,"column":1,"index":781},"filename":"function-expression-mutation-edge-case.ts"},"fnName":"Component","memoSlots":9,"memoBlocks":4,"memoValues":5,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nState: [foo, bar]\n\nData Flow Tree:\n└── newData\n ├── foo (State)\n └── bar (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":23,"column":6,"index":663},"end":{"line":23,"column":12,"index":669},"filename":"function-expression-mutation-edge-case.ts","identifierName":"setFoo"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":64},"end":{"line":32,"column":1,"index":762},"filename":"function-expression-mutation-edge-case.ts"},"fnName":"Component","memoSlots":9,"memoBlocks":4,"memoValues":5,"prunedMemoBlocks":0,"prunedMemoValues":0}
```
### Eval output

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
function Component() {
const [foo, setFoo] = useState({});

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
function Component() {
@@ -28,20 +28,38 @@ export const FIXTURE_ENTRYPOINT = {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import { useEffect, useState } from "react";
function Component() {
const [firstName, setFirstName] = useState("Taylor");
const lastName = "Swift";
const $ = _c(5);
const [firstName] = useState("Taylor");
// 🔴 Avoid: redundant state and unnecessary Effect
const [fullName, setFullName] = useState("");
useEffect(() => {
setFullName(firstName + " " + lastName);
}, [firstName, lastName]);
return <div>{fullName}</div>;
let t0;
let t1;
if ($[0] !== firstName) {
t0 = () => {
setFullName(firstName + " " + "Swift");
};
t1 = [firstName, "Swift"];
$[0] = firstName;
$[1] = t0;
$[2] = t1;
} else {
t0 = $[1];
t1 = $[2];
}
useEffect(t0, t1);
let t2;
if ($[3] !== fullName) {
t2 = <div>{fullName}</div>;
$[3] = fullName;
$[4] = t2;
} else {
t2 = $[4];
}
return t2;
}
export const FIXTURE_ENTRYPOINT = {
@@ -54,8 +72,8 @@ export const FIXTURE_ENTRYPOINT = {
## Logs
```
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nState: [firstName]\n\nData Flow Tree:\n└── firstName (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":11,"column":4,"index":360},"end":{"line":11,"column":15,"index":371},"filename":"invalid-derived-computation-in-effect.ts","identifierName":"setFullName"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":15,"column":1,"index":464},"filename":"invalid-derived-computation-in-effect.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nState: [firstName]\n\nData Flow Tree:\n└── firstName (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":11,"column":4,"index":341},"end":{"line":11,"column":15,"index":352},"filename":"invalid-derived-computation-in-effect.ts","identifierName":"setFullName"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":15,"column":1,"index":445},"filename":"invalid-derived-computation-in-effect.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
```
### Eval output

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
function Component() {

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
export default function Component(props) {
@@ -26,18 +26,39 @@ export const FIXTURE_ENTRYPOINT = {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import { useEffect, useState } from "react";
export default function Component(props) {
const $ = _c(7);
const [displayValue, setDisplayValue] = useState("");
useEffect(() => {
const computed = props.prefix + props.value + props.suffix;
setDisplayValue(computed);
}, [props.prefix, props.value, props.suffix]);
return <div>{displayValue}</div>;
let t0;
let t1;
if ($[0] !== props.prefix || $[1] !== props.suffix || $[2] !== props.value) {
t0 = () => {
const computed = props.prefix + props.value + props.suffix;
setDisplayValue(computed);
};
t1 = [props.prefix, props.value, props.suffix];
$[0] = props.prefix;
$[1] = props.suffix;
$[2] = props.value;
$[3] = t0;
$[4] = t1;
} else {
t0 = $[3];
t1 = $[4];
}
useEffect(t0, t1);
let t2;
if ($[5] !== displayValue) {
t2 = <div>{displayValue}</div>;
$[5] = displayValue;
$[6] = t2;
} else {
t2 = $[6];
}
return t2;
}
export const FIXTURE_ENTRYPOINT = {
@@ -50,8 +71,8 @@ export const FIXTURE_ENTRYPOINT = {
## Logs
```
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [props]\n\nData Flow Tree:\n└── computed\n └── props (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":9,"column":4,"index":314},"end":{"line":9,"column":19,"index":329},"filename":"invalid-derived-state-from-computed-props.ts","identifierName":"setDisplayValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":141},"end":{"line":13,"column":1,"index":428},"filename":"invalid-derived-state-from-computed-props.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [props]\n\nData Flow Tree:\n└── computed\n └── props (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":9,"column":4,"index":295},"end":{"line":9,"column":19,"index":310},"filename":"invalid-derived-state-from-computed-props.ts","identifierName":"setDisplayValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":122},"end":{"line":13,"column":1,"index":409},"filename":"invalid-derived-state-from-computed-props.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
```
### Eval output

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
export default function Component(props) {

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
export default function Component({props}) {
@@ -27,19 +27,40 @@ export const FIXTURE_ENTRYPOINT = {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import { useEffect, useState } from "react";
export default function Component({ props }) {
export default function Component(t0) {
const $ = _c(6);
const { props } = t0;
const [fullName, setFullName] = useState(
props.firstName + " " + props.lastName,
);
useEffect(() => {
setFullName(props.firstName + " " + props.lastName);
}, [props.firstName, props.lastName]);
return <div>{fullName}</div>;
let t1;
let t2;
if ($[0] !== props.firstName || $[1] !== props.lastName) {
t1 = () => {
setFullName(props.firstName + " " + props.lastName);
};
t2 = [props.firstName, props.lastName];
$[0] = props.firstName;
$[1] = props.lastName;
$[2] = t1;
$[3] = t2;
} else {
t1 = $[2];
t2 = $[3];
}
useEffect(t1, t2);
let t3;
if ($[4] !== fullName) {
t3 = <div>{fullName}</div>;
$[4] = fullName;
$[5] = t3;
} else {
t3 = $[5];
}
return t3;
}
export const FIXTURE_ENTRYPOINT = {
@@ -52,8 +73,8 @@ export const FIXTURE_ENTRYPOINT = {
## Logs
```
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [props]\n\nData Flow Tree:\n└── props (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":10,"column":4,"index":288},"end":{"line":10,"column":15,"index":299},"filename":"invalid-derived-state-from-destructured-props.ts","identifierName":"setFullName"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":141},"end":{"line":14,"column":1,"index":416},"filename":"invalid-derived-state-from-destructured-props.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [props]\n\nData Flow Tree:\n└── props (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":10,"column":4,"index":269},"end":{"line":10,"column":15,"index":280},"filename":"invalid-derived-state-from-destructured-props.ts","identifierName":"setFullName"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":122},"end":{"line":14,"column":1,"index":397},"filename":"invalid-derived-state-from-destructured-props.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
```
### Eval output

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState} from 'react';
export default function Component({props}) {

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState, useRef} from 'react';
export default function Component({test}) {
@@ -31,23 +31,44 @@ export const FIXTURE_ENTRYPOINT = {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import { useEffect, useState, useRef } from "react";
export default function Component({ test }) {
export default function Component(t0) {
const $ = _c(5);
const { test } = t0;
const [local, setLocal] = useState(0);
const myRef = useRef(null);
let t1;
let t2;
if ($[0] !== test) {
t1 = () => {
if (myRef.current) {
setLocal(test);
} else {
setLocal(test + test);
}
};
useEffect(() => {
if (myRef.current) {
setLocal(test);
} else {
setLocal(test + test);
}
}, [test]);
return <>{local}</>;
t2 = [test];
$[0] = test;
$[1] = t1;
$[2] = t2;
} else {
t1 = $[1];
t2 = $[2];
}
useEffect(t1, t2);
let t3;
if ($[3] !== local) {
t3 = <>{local}</>;
$[3] = local;
$[4] = t3;
} else {
t3 = $[4];
}
return t3;
}
export const FIXTURE_ENTRYPOINT = {
@@ -60,7 +81,7 @@ export const FIXTURE_ENTRYPOINT = {
## Logs
```
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":149},"end":{"line":18,"column":1,"index":405},"filename":"ref-conditional-in-effect-no-error.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":130},"end":{"line":18,"column":1,"index":386},"filename":"ref-conditional-in-effect-no-error.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
```
### Eval output

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
import {useEffect, useState, useRef} from 'react';
export default function Component({test}) {

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
function Component({prop}) {
const [s, setS] = useState();
@@ -26,23 +26,37 @@ function Component({prop}) {
## Code
```javascript
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
function Component({ prop }) {
function Component(t0) {
const $ = _c(5);
const { prop } = t0;
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>;
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;
}
```
@@ -50,8 +64,8 @@ function Component({ prop }) {
## Logs
```
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nState: [second]\n\nData Flow Tree:\n└── second (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":14,"column":4,"index":462},"end":{"line":14,"column":8,"index":466},"filename":"usestate-derived-from-prop-no-show-in-data-flow-tree.ts","identifierName":"setS"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":83},"end":{"line":18,"column":1,"index":519},"filename":"usestate-derived-from-prop-no-show-in-data-flow-tree.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nState: [second]\n\nData Flow Tree:\n└── second (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":14,"column":4,"index":443},"end":{"line":14,"column":8,"index":447},"filename":"usestate-derived-from-prop-no-show-in-data-flow-tree.ts","identifierName":"setS"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":64},"end":{"line":18,"column":1,"index":500},"filename":"usestate-derived-from-prop-no-show-in-data-flow-tree.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
```
### Eval output

View File

@@ -1,4 +1,4 @@
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
function Component({prop}) {
const [s, setS] = useState();

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoJSXInTryStatements @outputMode:"lint"
// @validateNoJSXInTryStatements
import {identity} from 'shared-runtime';
function Component(props) {

View File

@@ -1,4 +1,4 @@
// @validateNoJSXInTryStatements @outputMode:"lint"
// @validateNoJSXInTryStatements
import {identity} from 'shared-runtime';
function Component(props) {

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateNoJSXInTryStatements @outputMode:"lint"
// @validateNoJSXInTryStatements
function Component(props) {
let el;
try {

View File

@@ -1,4 +1,4 @@
// @validateNoJSXInTryStatements @outputMode:"lint"
// @validateNoJSXInTryStatements
function Component(props) {
let el;
try {

View File

@@ -10,28 +10,14 @@ function Component({prop1, prop2}) {
const y = x * 2;
const arr = [x, y];
const obj = {x, y};
let destA, destB;
if (y > 5) {
[destA, destB] = arr;
}
const [a, b] = arr;
const {x: c, y: d} = obj;
let sound;
if (y > 10) {
sound = 'woof';
} else {
sound = 'meow';
}
useEffect(() => {
if (a > 10) {
console.log(a);
console.log(sound);
console.log(destA, destB);
}
}, [a, sound, destA, destB]);
}, [a]);
const foo = useCallback(() => {
return a + b;
@@ -52,343 +38,187 @@ function Component({prop1, prop2}) {
## Error
```
Found 25 errors:
Found 13 errors:
Todo: Important source location missing in generated code
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
Source location for VariableDeclarator is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:4:9
2 | import {useEffect, useCallback} from 'react';
error.todo-missing-source-locations.ts:5:8
3 |
> 4 | function Component({prop1, prop2}) {
| ^^^^^^^^^
5 | const x = prop1 + prop2;
4 | function Component({prop1, prop2}) {
> 5 | const x = prop1 + prop2;
| ^^^^^^^^^^^^^^^^^
6 | const y = x * 2;
7 | const arr = [x, y];
8 | const obj = {x, y};
Todo: Important source location missing in generated code
Source location for VariableDeclaration is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
Source location for VariableDeclarator is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:9:2
error.todo-missing-source-locations.ts:6:8
4 | function Component({prop1, prop2}) {
5 | const x = prop1 + prop2;
> 6 | const y = x * 2;
| ^^^^^^^^^
7 | const arr = [x, y];
8 | const obj = {x, y};
9 | const [a, b] = arr;
Todo: Important source location missing in generated code
Source location for VariableDeclarator is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:7:8
5 | const x = prop1 + prop2;
6 | const y = x * 2;
> 7 | const arr = [x, y];
| ^^^^^^^^^^^^
8 | const obj = {x, y};
9 | const [a, b] = arr;
10 | const {x: c, y: d} = obj;
Todo: Important source location missing in generated code
Source location for VariableDeclarator is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:8:8
6 | const y = x * 2;
7 | const arr = [x, y];
> 8 | const obj = {x, y};
| ^^^^^^^^^^^^
9 | const [a, b] = arr;
10 | const {x: c, y: d} = obj;
11 |
Todo: Important source location missing in generated code
Source location for VariableDeclarator is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:9:8
7 | const arr = [x, y];
8 | const obj = {x, y};
> 9 | let destA, destB;
> 9 | const [a, b] = arr;
| ^^^^^^^^^^^^
10 | const {x: c, y: d} = obj;
11 |
12 | useEffect(() => {
Todo: Important source location missing in generated code
Source location for VariableDeclarator is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:10:8
8 | const obj = {x, y};
9 | const [a, b] = arr;
> 10 | const {x: c, y: d} = obj;
| ^^^^^^^^^^^^^^^^^^
11 |
12 | useEffect(() => {
13 | if (a > 10) {
Todo: Important source location missing in generated code
Source location for ExpressionStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:12:2
10 | const {x: c, y: d} = obj;
11 |
> 12 | useEffect(() => {
| ^^^^^^^^^^^^^^^^^
10 | if (y > 5) {
11 | [destA, destB] = arr;
12 | }
> 13 | if (a > 10) {
| ^^^^^^^^^^^^^^^^^
> 14 | console.log(a);
| ^^^^^^^^^^^^^^^^^
> 15 | }
| ^^^^^^^^^^^^^^^^^
> 16 | }, [a]);
| ^^^^^^^^^^^
17 |
18 | const foo = useCallback(() => {
19 | return a + b;
Todo: Important source location missing in generated code
Source location for ExpressionStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:11:4
9 | let destA, destB;
10 | if (y > 5) {
> 11 | [destA, destB] = arr;
| ^^^^^^^^^^^^^^^^^^^^^
12 | }
13 |
14 | const [a, b] = arr;
Todo: Important source location missing in generated code
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:15:9
13 |
14 | const [a, b] = arr;
> 15 | const {x: c, y: d} = obj;
| ^
16 | let sound;
17 |
18 | if (y > 10) {
Todo: Important source location missing in generated code
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:15:15
13 |
14 | const [a, b] = arr;
> 15 | const {x: c, y: d} = obj;
| ^
16 | let sound;
17 |
18 | if (y > 10) {
Todo: Important source location missing in generated code
Source location for VariableDeclaration is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:16:2
14 | const [a, b] = arr;
15 | const {x: c, y: d} = obj;
> 16 | let sound;
| ^^^^^^^^^^
17 |
18 | if (y > 10) {
19 | sound = 'woof';
Todo: Important source location missing in generated code
Source location for ExpressionStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:19:4
17 |
18 | if (y > 10) {
> 19 | sound = 'woof';
| ^^^^^^^^^^^^^^^
20 | } else {
21 | sound = 'meow';
22 | }
Todo: Important source location has wrong node type in generated code
Source location for Identifier exists in the generated output but with wrong node type(s): ExpressionStatement. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:19:4
17 |
18 | if (y > 10) {
> 19 | sound = 'woof';
| ^^^^^
20 | } else {
21 | sound = 'meow';
22 | }
Todo: Important source location missing in generated code
Source location for ExpressionStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:21:4
19 | sound = 'woof';
20 | } else {
> 21 | sound = 'meow';
| ^^^^^^^^^^^^^^^
22 | }
23 |
24 | useEffect(() => {
Todo: Important source location has wrong node type in generated code
Source location for Identifier exists in the generated output but with wrong node type(s): ExpressionStatement. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:21:4
19 | sound = 'woof';
20 | } else {
> 21 | sound = 'meow';
| ^^^^^
22 | }
23 |
24 | useEffect(() => {
Todo: Important source location missing in generated code
Source location for ExpressionStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:24:2
22 | }
23 |
> 24 | useEffect(() => {
| ^^^^^^^^^^^^^^^^^
> 25 | if (a > 10) {
| ^^^^^^^^^^^^^^^^^
> 26 | console.log(a);
| ^^^^^^^^^^^^^^^^^
> 27 | console.log(sound);
| ^^^^^^^^^^^^^^^^^
> 28 | console.log(destA, destB);
| ^^^^^^^^^^^^^^^^^
> 29 | }
| ^^^^^^^^^^^^^^^^^
> 30 | }, [a, sound, destA, destB]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
31 |
32 | const foo = useCallback(() => {
33 | return a + b;
Todo: Important source location missing in generated code
Source location for ExpressionStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:26:6
24 | useEffect(() => {
25 | if (a > 10) {
> 26 | console.log(a);
error.todo-missing-source-locations.ts:14:6
12 | useEffect(() => {
13 | if (a > 10) {
> 14 | console.log(a);
| ^^^^^^^^^^^^^^^
27 | console.log(sound);
28 | console.log(destA, destB);
29 | }
15 | }
16 | }, [a]);
17 |
Todo: Important source location missing in generated code
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
Source location for VariableDeclarator is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:26:14
24 | useEffect(() => {
25 | if (a > 10) {
> 26 | console.log(a);
| ^^^
27 | console.log(sound);
28 | console.log(destA, destB);
29 | }
Todo: Important source location missing in generated code
Source location for ExpressionStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:27:6
25 | if (a > 10) {
26 | console.log(a);
> 27 | console.log(sound);
| ^^^^^^^^^^^^^^^^^^^
28 | console.log(destA, destB);
29 | }
30 | }, [a, sound, destA, destB]);
Todo: Important source location missing in generated code
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:27:14
25 | if (a > 10) {
26 | console.log(a);
> 27 | console.log(sound);
| ^^^
28 | console.log(destA, destB);
29 | }
30 | }, [a, sound, destA, destB]);
Todo: Important source location missing in generated code
Source location for ExpressionStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:28:6
26 | console.log(a);
27 | console.log(sound);
> 28 | console.log(destA, destB);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
29 | }
30 | }, [a, sound, destA, destB]);
31 |
Todo: Important source location missing in generated code
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:28:14
26 | console.log(a);
27 | console.log(sound);
> 28 | console.log(destA, destB);
| ^^^
29 | }
30 | }, [a, sound, destA, destB]);
31 |
Todo: Important source location missing in generated code
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:32:14
30 | }, [a, sound, destA, destB]);
31 |
> 32 | const foo = useCallback(() => {
| ^^^^^^^^^^^
33 | return a + b;
34 | }, [a, b]);
35 |
error.todo-missing-source-locations.ts:18:8
16 | }, [a]);
17 |
> 18 | const foo = useCallback(() => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
> 19 | return a + b;
| ^^^^^^^^^^^^^^^^^
> 20 | }, [a, b]);
| ^^^^^^^^^^^^^
21 |
22 | function bar() {
23 | return (c + d) * 2;
Todo: Important source location missing in generated code
Source location for ReturnStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:33:4
31 |
32 | const foo = useCallback(() => {
> 33 | return a + b;
error.todo-missing-source-locations.ts:19:4
17 |
18 | const foo = useCallback(() => {
> 19 | return a + b;
| ^^^^^^^^^^^^^
34 | }, [a, b]);
35 |
36 | function bar() {
Todo: Important source location missing in generated code
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:34:6
32 | const foo = useCallback(() => {
33 | return a + b;
> 34 | }, [a, b]);
| ^
35 |
36 | function bar() {
37 | return (c + d) * 2;
Todo: Important source location missing in generated code
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:34:9
32 | const foo = useCallback(() => {
33 | return a + b;
> 34 | }, [a, b]);
| ^
35 |
36 | function bar() {
37 | return (c + d) * 2;
20 | }, [a, b]);
21 |
22 | function bar() {
Todo: Important source location missing in generated code
Source location for ReturnStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:37:4
35 |
36 | function bar() {
> 37 | return (c + d) * 2;
error.todo-missing-source-locations.ts:23:4
21 |
22 | function bar() {
> 23 | return (c + d) * 2;
| ^^^^^^^^^^^^^^^^^^^
38 | }
39 |
40 | console.log('Hello, world!');
24 | }
25 |
26 | console.log('Hello, world!');
Todo: Important source location missing in generated code
Source location for ExpressionStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:40:2
38 | }
39 |
> 40 | console.log('Hello, world!');
error.todo-missing-source-locations.ts:26:2
24 | }
25 |
> 26 | console.log('Hello, world!');
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
41 |
42 | return [y, foo, bar];
43 | }
Todo: Important source location missing in generated code
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:40:10
38 | }
39 |
> 40 | console.log('Hello, world!');
| ^^^
41 |
42 | return [y, foo, bar];
43 | }
27 |
28 | return [y, foo, bar];
29 | }
Todo: Important source location missing in generated code
Source location for ReturnStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:42:2
40 | console.log('Hello, world!');
41 |
> 42 | return [y, foo, bar];
error.todo-missing-source-locations.ts:28:2
26 | console.log('Hello, world!');
27 |
> 28 | return [y, foo, bar];
| ^^^^^^^^^^^^^^^^^^^^^
43 | }
44 |
29 | }
30 |
```

View File

@@ -6,28 +6,14 @@ function Component({prop1, prop2}) {
const y = x * 2;
const arr = [x, y];
const obj = {x, y};
let destA, destB;
if (y > 5) {
[destA, destB] = arr;
}
const [a, b] = arr;
const {x: c, y: d} = obj;
let sound;
if (y > 10) {
sound = 'woof';
} else {
sound = 'meow';
}
useEffect(() => {
if (a > 10) {
console.log(a);
console.log(sound);
console.log(destA, destB);
}
}, [a, sound, destA, destB]);
}, [a]);
const foo = useCallback(() => {
return a + b;

View File

@@ -44,6 +44,7 @@ function Component(props) {
let t0;
if ($[0] !== props.a) {
const a = [props.a];
t0 = [a];
$[0] = props.a;
$[1] = t0;

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateExhaustiveEffectDependencies:"all"
// @validateExhaustiveEffectDependencies
import {useEffect, useEffectEvent} from 'react';
function Component({x, y, z}) {

View File

@@ -1,4 +1,4 @@
// @validateExhaustiveEffectDependencies:"all"
// @validateExhaustiveEffectDependencies
import {useEffect, useEffectEvent} from 'react';
function Component({x, y, z}) {

View File

@@ -1,83 +0,0 @@
## Input
```javascript
// @validateExhaustiveEffectDependencies:"extra-only"
import {useEffect} from 'react';
function Component({x, y, z}) {
// no error: missing dep not reported in extra-only mode
useEffect(() => {
log(x);
}, []);
// error: extra dep - y
useEffect(() => {
log(x);
}, [x, y]);
// error: extra dep - y (missing dep - z not reported)
useEffect(() => {
log(x, z);
}, [x, y]);
// error: extra dep - x.y
useEffect(() => {
log(x);
}, [x.y]);
}
```
## Error
```
Found 3 errors:
Error: Found extra effect dependencies
Extra dependencies can cause an effect to fire more often than it should, resulting in performance problems such as excessive renders and side effects.
error.invalid-exhaustive-effect-deps-extra-only.ts:13:9
11 | useEffect(() => {
12 | log(x);
> 13 | }, [x, y]);
| ^ Unnecessary dependency `y`
14 |
15 | // error: extra dep - y (missing dep - z not reported)
16 | useEffect(() => {
Inferred dependencies: `[x]`
Error: Found extra effect dependencies
Extra dependencies can cause an effect to fire more often than it should, resulting in performance problems such as excessive renders and side effects.
error.invalid-exhaustive-effect-deps-extra-only.ts:18:9
16 | useEffect(() => {
17 | log(x, z);
> 18 | }, [x, y]);
| ^ Unnecessary dependency `y`
19 |
20 | // error: extra dep - x.y
21 | useEffect(() => {
Inferred dependencies: `[x, z]`
Error: Found extra effect dependencies
Extra dependencies can cause an effect to fire more often than it should, resulting in performance problems such as excessive renders and side effects.
error.invalid-exhaustive-effect-deps-extra-only.ts:23:6
21 | useEffect(() => {
22 | log(x);
> 23 | }, [x.y]);
| ^^^ Overly precise dependency `x.y`, use `x` instead
24 | }
25 |
Inferred dependencies: `[x]`
```

View File

@@ -1,24 +0,0 @@
// @validateExhaustiveEffectDependencies:"extra-only"
import {useEffect} from 'react';
function Component({x, y, z}) {
// no error: missing dep not reported in extra-only mode
useEffect(() => {
log(x);
}, []);
// error: extra dep - y
useEffect(() => {
log(x);
}, [x, y]);
// error: extra dep - y (missing dep - z not reported)
useEffect(() => {
log(x, z);
}, [x, y]);
// error: extra dep - x.y
useEffect(() => {
log(x);
}, [x.y]);
}

View File

@@ -1,84 +0,0 @@
## Input
```javascript
// @validateExhaustiveEffectDependencies:"missing-only"
import {useEffect} from 'react';
function Component({x, y, z}) {
// error: missing dep - x
useEffect(() => {
log(x);
}, []);
// no error: extra dep not reported in missing-only mode
useEffect(() => {
log(x);
}, [x, y]);
// error: missing dep - z (extra dep - y not reported)
useEffect(() => {
log(x, z);
}, [x, y]);
// error: missing dep x
useEffect(() => {
log(x);
}, [x.y]);
}
```
## Error
```
Found 3 errors:
Error: Found missing effect dependencies
Missing dependencies can cause an effect to fire less often than it should.
error.invalid-exhaustive-effect-deps-missing-only.ts:7:8
5 | // error: missing dep - x
6 | useEffect(() => {
> 7 | log(x);
| ^ Missing dependency `x`
8 | }, []);
9 |
10 | // no error: extra dep not reported in missing-only mode
Inferred dependencies: `[x]`
Error: Found missing effect dependencies
Missing dependencies can cause an effect to fire less often than it should.
error.invalid-exhaustive-effect-deps-missing-only.ts:17:11
15 | // error: missing dep - z (extra dep - y not reported)
16 | useEffect(() => {
> 17 | log(x, z);
| ^ Missing dependency `z`
18 | }, [x, y]);
19 |
20 | // error: missing dep x
Inferred dependencies: `[x, z]`
Error: Found missing effect dependencies
Missing dependencies can cause an effect to fire less often than it should.
error.invalid-exhaustive-effect-deps-missing-only.ts:22:8
20 | // error: missing dep x
21 | useEffect(() => {
> 22 | log(x);
| ^ Missing dependency `x`
23 | }, [x.y]);
24 | }
25 |
Inferred dependencies: `[x]`
```

View File

@@ -1,24 +0,0 @@
// @validateExhaustiveEffectDependencies:"missing-only"
import {useEffect} from 'react';
function Component({x, y, z}) {
// error: missing dep - x
useEffect(() => {
log(x);
}, []);
// no error: extra dep not reported in missing-only mode
useEffect(() => {
log(x);
}, [x, y]);
// error: missing dep - z (extra dep - y not reported)
useEffect(() => {
log(x, z);
}, [x, y]);
// error: missing dep x
useEffect(() => {
log(x);
}, [x.y]);
}

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateExhaustiveEffectDependencies:"all"
// @validateExhaustiveEffectDependencies
import {useEffect} from 'react';
function Component({x, y, z}) {

View File

@@ -1,4 +1,4 @@
// @validateExhaustiveEffectDependencies:"all"
// @validateExhaustiveEffectDependencies
import {useEffect} from 'react';
function Component({x, y, z}) {

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateExhaustiveMemoizationDependencies @validateExhaustiveEffectDependencies:"all"
// @validateExhaustiveMemoizationDependencies @validateExhaustiveEffectDependencies
import {
useCallback,
useTransition,
@@ -69,7 +69,7 @@ export const FIXTURE_ENTRYPOINT = {
## Code
```javascript
import { c as _c } from "react/compiler-runtime"; // @validateExhaustiveMemoizationDependencies @validateExhaustiveEffectDependencies:"all"
import { c as _c } from "react/compiler-runtime"; // @validateExhaustiveMemoizationDependencies @validateExhaustiveEffectDependencies
import {
useCallback,
useTransition,

View File

@@ -1,4 +1,4 @@
// @validateExhaustiveMemoizationDependencies @validateExhaustiveEffectDependencies:"all"
// @validateExhaustiveMemoizationDependencies @validateExhaustiveEffectDependencies
import {
useCallback,
useTransition,

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @validateExhaustiveEffectDependencies:"all"
// @validateExhaustiveEffectDependencies
import {useEffect, useEffectEvent} from 'react';
function Component({x, y, z}) {
@@ -30,7 +30,7 @@ function Component({x, y, z}) {
## Code
```javascript
import { c as _c } from "react/compiler-runtime"; // @validateExhaustiveEffectDependencies:"all"
import { c as _c } from "react/compiler-runtime"; // @validateExhaustiveEffectDependencies
import { useEffect, useEffectEvent } from "react";
function Component(t0) {

View File

@@ -1,4 +1,4 @@
// @validateExhaustiveEffectDependencies:"all"
// @validateExhaustiveEffectDependencies
import {useEffect, useEffectEvent} from 'react';
function Component({x, y, z}) {

View File

@@ -40,11 +40,13 @@ function Component(props) {
[
fbt._param(
"a really long description that got split into multiple lines",
props.name,
),
],
{ hk: "1euPUp" },
);
t0 = element.toString();
$[0] = props.name;
$[1] = t0;

View File

@@ -32,9 +32,16 @@ function Component(props) {
if ($[0] !== props.name) {
const element = fbt._(
'Hello {"user" name}',
[fbt._param('"user" name', props.name)],
[
fbt._param(
'"user" name',
props.name,
),
],
{ hk: "S0vMe" },
);
t0 = element.toString();
$[0] = props.name;
$[1] = t0;

View File

@@ -32,9 +32,16 @@ function Component(props) {
if ($[0] !== props.name) {
const element = fbt._(
"Hello {user name ☺}",
[fbt._param("user name \u263A", props.name)],
[
fbt._param(
"user name \u263A",
props.name,
),
],
{ hk: "1En1lp" },
);
t0 = element.toString();
$[0] = props.name;
$[1] = t0;

Some files were not shown because too many files have changed in this diff Show More