Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Introducing a new hook useDeferredState #251

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
111 changes: 111 additions & 0 deletions text/0000-use-deferred-state.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
- Start Date: 2023-07-19
- RFC PR: (leave this empty)
- React Issue: (leave this empty)

# Summary

This proposal suggests simplifying the usage of `startTransition` in `React` by
introducing a new hook.

# Basic example

Currently, in order to utilize `startTransition`, developers need to
import `useTransition` and set it up as follows:

```js
const [isPending, startTransition] = useTransition();
```

However, in some cases, the `isPending` value is not used, but it still needs to be included because `startTransition` occupies the second index of the `useTransition` output. Additionally, `startTransition` often needs to work in conjunction with `useState`.

To address these complexities, I propose combining these hooks into a new one named `useDeferredState`

```js
const [text, setText, isPending] = useDeferredState();
```

Alternatively, we can achieve the same result using a HOF to wrap `useState`, like this:

```js
const [text, setText, isPending] = deferred(useState());
```

# Motivation
The main motivation behind this proposal is to streamline the usage of `useTransition` and `startTransition` in `React`, making it more straightforward and intuitive for developers. By introducing a new hook or a HOF, we can enhance the developer experience and promote cleaner, more concise code when working with transitions in React.

# Detailed design
`useDeferredState` and `deferred` are a combination of two main React hooks `useState` and `useTransition`.

By placing `isPending` as the third element in the output, it provides the flexibility to choose whether or not to utilize it in your code:
```js
// Use 'isPending' when needed:
const [text, setText, isPending] = useDeferredState();

// Omit 'isPending' when not required:
const [text, setText] = useDeferredState();
```

# Drawbacks

- I think teaching `useTransition` is much harder than teaching `useDeferredState`
- There is no breaking chaneg therefore there is no cost of migrating existing React applications.

# Alternatives

An alternative solution is having `useDeferredState` or `deferred` as
a 3th-party package.

```js
const useDeferredState = (initialValue) => {
const [state, _setState] = useState(initialValue);
const [isPenfing, startTransition] = useTransition();

const setState = useCallback((newValue) => {
startTransition(() => {
_setState(newValue);
});
}, []);

return [state, setState, isPenfing];
}

// usage:
const [text, setText, isPending] = useDeferredState();
```

or

```js
const deferred = ([state, _setState]) => {
const [isPenfing, startTransition] = useTransition();

const setState = useCallback((newValue) => {
startTransition(() => {
_setState(newValue);
});
}, []);

return [state, setState, isPenfing];
}

// usage:
const [text, setText, isPending] = deferred(useState());
```

# Adoption strategy

The proposed hook and Higher-Order Function are opt-in features, meaning that developers can
choose whether or not to use them in their code. Existing React applications that don't require
the new functionalities can continue using the traditional `useState` and `useTransition` approaches
without any changes.

# How we teach this

`useDeferredState`:
The proposed hook combines `useState` with a deferred state update mechanism to handle non-urgent updates. The term `deferred` accurately describes the behavior of the state update, as it delays execution until a later time (when React is less busy). This name aligns with React's existing hooks, such as `useEffect`, which also involve deferred operations.

`deferred`:
When introducing the Higher-Order Function, it wraps useState to achieve similar functionality to the `useDeferredState` hook. The name `deferred` directly reflects the primary purpose of the function, emphasizing its role in handling state updates in a deferred manner.

# Unresolved questions
Is there any downside if we use multiple `useTransition` in a component?