Compare commits

...

1 Commits

Author SHA1 Message Date
Joe Savona
b56252672a [compiler] disallow ref access in state initializer, reducer/initializer
Per title, disallow ref access in `useState()` initializer function, `useReducer()` reducer, and `useReducer()` init function.
2025-07-29 10:55:24 -07:00
7 changed files with 176 additions and 1 deletions

View File

@@ -434,7 +434,12 @@ function validateNoRefAccessInRenderImpl(
* By default we check that function call operands are not refs,
* ref values, or functions that can access refs.
*/
if (isRefLValue || hookKind != null) {
if (
isRefLValue ||
(hookKind != null &&
hookKind !== 'useState' &&
hookKind !== 'useReducer')
) {
/**
* Special cases:
*

View File

@@ -0,0 +1,45 @@
## Input
```javascript
import {useReducer, useRef} from 'react';
function Component(props) {
const ref = useRef(props.value);
const [state] = useReducer(
(state, action) => state + action,
0,
init => ref.current
);
return <Stringify state={state} />;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 42}],
};
```
## Error
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
error.invalid-access-ref-in-reducer-init.ts:8:4
6 | (state, action) => state + action,
7 | 0,
> 8 | init => ref.current
| ^^^^^^^^^^^^^^^^^^^ Passing a ref to a function may read its value during render
9 | );
10 |
11 | return <Stringify state={state} />;
```

View File

@@ -0,0 +1,17 @@
import {useReducer, useRef} from 'react';
function Component(props) {
const ref = useRef(props.value);
const [state] = useReducer(
(state, action) => state + action,
0,
init => ref.current
);
return <Stringify state={state} />;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 42}],
};

View File

@@ -0,0 +1,41 @@
## Input
```javascript
import {useReducer, useRef} from 'react';
function Component(props) {
const ref = useRef(props.value);
const [state] = useReducer(() => ref.current, null);
return <Stringify state={state} />;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 42}],
};
```
## Error
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
error.invalid-access-ref-in-reducer.ts:5:29
3 | function Component(props) {
4 | const ref = useRef(props.value);
> 5 | const [state] = useReducer(() => ref.current, null);
| ^^^^^^^^^^^^^^^^^ Passing a ref to a function may read its value during render
6 |
7 | return <Stringify state={state} />;
8 | }
```

View File

@@ -0,0 +1,13 @@
import {useReducer, useRef} from 'react';
function Component(props) {
const ref = useRef(props.value);
const [state] = useReducer(() => ref.current, null);
return <Stringify state={state} />;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 42}],
};

View File

@@ -0,0 +1,41 @@
## Input
```javascript
import {useRef, useState} from 'react';
function Component(props) {
const ref = useRef(props.value);
const [state] = useState(() => ref.current);
return <Stringify state={state} />;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 42}],
};
```
## Error
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
error.invalid-access-ref-in-state-initializer.ts:5:27
3 | function Component(props) {
4 | const ref = useRef(props.value);
> 5 | const [state] = useState(() => ref.current);
| ^^^^^^^^^^^^^^^^^ Passing a ref to a function may read its value during render
6 |
7 | return <Stringify state={state} />;
8 | }
```

View File

@@ -0,0 +1,13 @@
import {useRef, useState} from 'react';
function Component(props) {
const ref = useRef(props.value);
const [state] = useState(() => ref.current);
return <Stringify state={state} />;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 42}],
};