Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,23 @@ function compareDeps(
!inferred.path.some(token => token.property === 'current')))
) {
return CompareDependencyResult.Ok;
} else if (
isSubpath &&
inferred.path.length < source.path.length &&
source.path[inferred.path.length].optional &&
!source.path.some(token => token.property === 'current') &&
!inferred.path.some(token => token.property === 'current')
) {
/**
* When the inferred dependency is a prefix of the source dependency and the
* source continues with an optional property access (e.g. inferred `obj` vs
* source `obj?.id`), this is acceptable. The compiler may infer a less
* specific dependency because optional chain lowering introduces conditionals,
* but the user's more specific optional dependency is semantically correct —
* using `?.` acknowledges the conditionality and produces `undefined` when
* the base is nullish, so the memoization is safe.
*/
return CompareDependencyResult.Ok;
} else {
if (isSubpath) {
if (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@

## Input

```javascript
// @validatePreserveExistingMemoizationGuarantees
import {useCallback} from 'react';

function Component({obj}) {
const onClick = useCallback(() => {
if (obj?.id) {
console.log(obj.id);
}
}, [obj?.id]);
return <button onClick={onClick} />;
}

export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{obj: {id: 42}}],
};

```

## Code

```javascript
import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees
import { useCallback } from "react";

function Component(t0) {
const $ = _c(4);
const { obj } = t0;
let t1;
if ($[0] !== obj) {
t1 = () => {
if (obj?.id) {
console.log(obj.id);
}
};
$[0] = obj;
$[1] = t1;
} else {
t1 = $[1];
}

obj?.id;
const onClick = t1;
let t2;
if ($[2] !== onClick) {
t2 = <button onClick={onClick} />;
$[2] = onClick;
$[3] = t2;
} else {
t2 = $[3];
}
return t2;
}

export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{ obj: { id: 42 } }],
};

```

### Eval output
(kind: ok) <button></button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// @validatePreserveExistingMemoizationGuarantees
import {useCallback} from 'react';

function Component({obj}) {
const onClick = useCallback(() => {
if (obj?.id) {
console.log(obj.id);
}
}, [obj?.id]);
return <button onClick={onClick} />;
}

export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{obj: {id: 42}}],
};