Skip to content

Commit 5aa9d61

Browse files
committed
wip
1 parent e697626 commit 5aa9d61

File tree

1 file changed

+80
-3
lines changed

1 file changed

+80
-3
lines changed

src/content/blog/2025/04/01/react-labs-what-we-have-been-working-on-april-2025.md

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12897,18 +12897,95 @@ The IDE extension is still an early exploration, but we'll share our progress in
1289712897

1289812898
## Automatic Effect Dependencies {/*automatic-effect-dependencies*/}
1289912899

12900-
TODO
12900+
When we released hooks, we had three motivations:
12901+
12902+
- **Sharing code between components**: hooks replaced patterns like render props and higher-order components to allow you to reuse stateful logic without changing your component hierarchy.
12903+
- **Think in terms of function, not lifecycles**: hooks let you split one component into smaller functions based on what pieces are related (such as setting up a subscription or fetching data), rather than forcing a split based on lifecycle methods.
12904+
- **Support ahead-of-time compilation**: hooks were designed to support ahead-of-time compilation with less pitfalls causing unintention de-optimizations caused by lifecycle methods, and limitation of classes.
12905+
12906+
Since their release, hooks have been successful at *sharing code between components*. Hooks are now the favored way to share logic between components, and there are less use cases for render props and higher order components. Hooks have also been successful at supporting features like Fast Refresh that were not possible with class components.
12907+
12908+
### Effects can be hard {/*effects-can-be-hard*/}
12909+
12910+
Unfortunately, some hooks are still hard to think in terms of function instead of lifecycles. Effects specifically are still hard to understand and is the most common pain point we hear from developers. Last year, we spent a significant amount of time researching how effects were used, and how those use cases could be simplified and easier to understand.
12911+
12912+
We found that often, the confusion is from using an Effect when you don't need to. The [You Probably Don't Need an Effect guide](/TODO), covers many cases for when Effects are not the right solution. However, even when an Effect is the right fit for a problem, Effects can still be harder to understand than class component lifecyles.
12913+
12914+
We believe one of the reasons for confusion is the dependecy array, which allows developers to think of effects from the _components_ perspective (like a lifecycle), instead of the _effects_ point of view (what the effect does).
12915+
12916+
Let's look at an example [from the docs](/learn/lifecycle-of-reactive-effects#thinking-from-the-effects-perspective):
12917+
12918+
```js
12919+
useEffect(() => {
12920+
// Your Effect connected to the room specified with roomId...
12921+
const connection = createConnection(serverUrl, roomId);
12922+
connection.connect();
12923+
return () => {
12924+
// ...until it disconnected
12925+
connection.disconnect();
12926+
};
12927+
}, [roomId]);
12928+
```
12929+
12930+
Many users would read this code as "on mount, connect to the roomId. whenever `roomId` changes, disconnect to the old room and re-create the connection". However, this is thinking from the component's lifecycle perspective, which means you will need to think of every compoent lifecycle state to write the effect correctly. This can be difficult, so it's understandble that Effects seem harder than class lifecycles when using component perspecitve.
12931+
12932+
### Effects on easy mode {/*effects-on-easy-mode*/}
12933+
12934+
Instaed, it's better to think from the Effect's perspective. The effect doesn't know about about the component lifecycles. It only describes how to start synchronization and how to stop it. When users think of Effects in this way, their Effects tend to be easier to write, and more resilient to being started and stopped as many times as it’s needed.
12935+
12936+
We spend some time reseaching why Effects are thought of from the component perspective, and we think one of the resons is the depenedency array. Since you have to write it, it's right there and in your face reminding you of what you're "reacting" to and baiting you into thinking of the component props and state changing.
12937+
12938+
When we released hooks, we thought this might be the case, but knew it would be solved by ahead-of-time compilation of the depependencies. It's taken longer than expected, but with the React Compiler we can start inserting the dependencies for you:
12939+
12940+
```js
12941+
useEffect(() => {
12942+
const connection = createConnection(serverUrl, roomId);
12943+
connection.connect();
12944+
return () => {
12945+
connection.disconnect();
12946+
};
12947+
}); // compiler inserted dependencies.
12948+
```
12949+
12950+
With this code, the React Compiler can infer the dependecies for you and insert them automatically so you don't need to see or write them. With features like the IDE exension and `useEffectEvent`, we can provide a CodeLens to show you what the Compiler inserted for times you need to debug, or to optimize by removing a dependency.
12951+
12952+
Our hope is that automatically inserting dependies is not only easier to write, but that it also makes them easier to understand by forcing you to think in terms of what the effect does, and not in component lifecycles.
1290112953

1290212954
## Fragment Refs {/*fragment-refs*/}
1290312955

12956+
Many DOM APIs like those for event management, positioning, and focus are difficult to compose when writing with React. This often leads developers to reach for Effects, managing multiple Refs, or APIs like `findDOMNode` (removed in React 19).
12957+
12958+
We are exploring adding refs to Fragments that would point to a group of DOM elements, rather than just a single element. Our hope is that this will simplify managing multiple children and make it easier to write composable React code when calling DOM APIs.
12959+
12960+
Fragment refs are still being researched. We'll share more when we're closer to having the final API finished.
1290412961

1290512962
## Gesture Animations {/*gesture-animations*/}
1290612963

12907-
TODO
12964+
We're also researching ways to enhance View Transitions to support gesture animations such as swiping to open a menu, or scroll through a photo carosel.
12965+
12966+
Gestures present new challenges for a few reasons:
12967+
12968+
- **Gestures are continuous**: as you swipe the animation is tied to your finger placement time, rather than triggering and running to completion.
12969+
- **Gestures don't complete:**: when you release your finger gesture animtaions can run to completion, or revert to their original state (like when you only partially open a menu) depending on how far you go.
12970+
- **Gestures invert old and new**: while you're animating, you want the page you are animating from to stay "alive" and interactive. This inverts the browser View Transition model where the "old" state is a snapshot and the "new" state is the live DOM.
12971+
12972+
We have an approach we believe will work well, which may introduce a new API to trigger gesture transitions, but we're currently focused on shipping `<ViewTransition>` and re-visit gestures after it ships.
1290812973

1290912974
## Concurrent stores {/*concurrent-stores*/}
1291012975

12911-
TODO
12976+
When we released React 18 with concurrent rendering, we also released `useSyncExternalStore` so external store libraries that did not use React state or context could [support concurrent rendering](https://github.com/reactwg/react-18/discussions/70) by forcing a sync render when the store is updated.
12977+
12978+
Using `useSyncExternalStore` comes at a cost though, since it forces bail out from concurrent features like transitions, and forces existing content to show Suspense fallbacks.
12979+
12980+
Now that React 19 has shipped, we're re-visiting this problem space to create a primiative to fully support concurrent external stores with the `use` API:
12981+
12982+
```js
12983+
const value = use(store);
12984+
```
12985+
12986+
Our goal is to allow state stored outside of React to be read in render without tearing, and to work seamlessly with all of the concurrent features React offers.
12987+
12988+
This research is still early. We'll share more, and what the new APIs will look like, when we're further along.
1291212989

1291312990
---
1291412991

0 commit comments

Comments
 (0)