Skip to content

Commit 59d9e9c

Browse files
Merge remote-tracking branch 'origin/main' into tony/future-to-stable-plan
2 parents af01cd8 + 163e864 commit 59d9e9c

5 files changed

Lines changed: 101 additions & 11 deletions

File tree

.changeset/add-lifecycle-plugin.md

Lines changed: 0 additions & 10 deletions
This file was deleted.

docs/components/ChangelogContent.mdx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
1+
## 2026.04.15
2+
3+
Add lifecyclePlugin and useFocusEffect hook for activity focus/blur lifecycle [`39dbf81`](https://github.com/daangn/stackflow/commit/39dbf81472af06daa5c40da098e232c2fe3b4a92)
4+
5+
- `useFocusEffect(callback)` hook to register per-activity focus/blur callbacks
6+
- Detection and invocation in plugin `onChanged` (outside React render cycle)
7+
- `callbackRef` pattern for always-latest callback without `useCallback`
8+
- Error isolation via `runSafely()` for all user callbacks
9+
10+
Released packages:
11+
- 📦 [@stackflow/plugin-lifecycle@0.1.0](https://npmjs.com/package/@stackflow/plugin-lifecycle/v/0.1.0)
12+
13+
---
14+
15+
Add README documentation for plugin-lifecycle [`fce2047`](https://github.com/daangn/stackflow/commit/fce204702b876869764076f74246319623fb3e89)
16+
17+
Released packages:
18+
- 📦 [@stackflow/plugin-lifecycle@0.1.0](https://npmjs.com/package/@stackflow/plugin-lifecycle/v/0.1.0)
19+
20+
---
21+
122
## 2026.04.03
223

324
Fix intermittent incorrect transition state when `transitionDuration` is set to 0 by ensuring `now >= eventDate` in the initial aggregate call within `dispatchEvent`. [`0160f82`](https://github.com/daangn/stackflow/commit/0160f82738e45932d13715564c4d1da2c4698c18)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# @stackflow/plugin-lifecycle
2+
3+
## 0.1.0
4+
5+
### Minor Changes
6+
7+
- 39dbf81: Add lifecyclePlugin and useFocusEffect hook for activity focus/blur lifecycle
8+
9+
- `useFocusEffect(callback)` hook to register per-activity focus/blur callbacks
10+
- Detection and invocation in plugin `onChanged` (outside React render cycle)
11+
- `callbackRef` pattern for always-latest callback without `useCallback`
12+
- Error isolation via `runSafely()` for all user callbacks
13+
14+
### Patch Changes
15+
16+
- fce2047: Add README documentation for plugin-lifecycle
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# plugin-lifecycle
2+
3+
Stackflow plugin that provides `useFocusEffect`, a hook for running side-effects when an activity gains or loses focus.
4+
5+
## Setup
6+
7+
Add `lifecyclePlugin()` to your stackflow configuration:
8+
9+
```typescript
10+
import { stackflow } from "@stackflow/react";
11+
import { lifecyclePlugin } from "@stackflow/plugin-lifecycle";
12+
13+
const { Stack, useFlow } = stackflow({
14+
activities: {
15+
// ...
16+
},
17+
plugins: [
18+
lifecyclePlugin(),
19+
// ... other plugins
20+
],
21+
});
22+
```
23+
24+
## Usage
25+
26+
`useFocusEffect` runs a callback when the activity becomes active, and an optional cleanup when it loses focus (blur), unmounts, or the callback reference changes.
27+
28+
```tsx
29+
import { useFocusEffect } from "@stackflow/plugin-lifecycle";
30+
31+
function ArticleActivity({ articleId }) {
32+
useFocusEffect(() => {
33+
queryClient.invalidateQueries(["article", articleId]);
34+
35+
return () => {
36+
// optional cleanup on blur
37+
};
38+
});
39+
}
40+
```
41+
42+
To re-run the effect when dependencies change, wrap the callback in `useCallback`:
43+
44+
```tsx
45+
import { useCallback } from "react";
46+
import { useFocusEffect } from "@stackflow/plugin-lifecycle";
47+
48+
function ArticleActivity({ articleId }) {
49+
useFocusEffect(
50+
useCallback(() => {
51+
const sub = subscribe(articleId);
52+
return () => sub.unsubscribe();
53+
}, [articleId]),
54+
);
55+
}
56+
```
57+
58+
## When to use
59+
60+
- **`useFocusEffect`** — External side-effects that should fire immediately on activity transition: query invalidation, analytics events, cache warming.
61+
- **`useActiveEffect`** (`@stackflow/react`) — Effects that depend on a settled React tree: DOM manipulation, scroll restoration.
62+
63+
The key difference is timing: `useFocusEffect` runs from the plugin's `onChanged` handler (outside the React render cycle), so it executes immediately without waiting for React's deferred rendering.

extensions/plugin-lifecycle/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@stackflow/plugin-lifecycle",
3-
"version": "0.0.1",
3+
"version": "0.1.0",
44
"repository": {
55
"type": "git",
66
"url": "https://github.com/daangn/stackflow.git",

0 commit comments

Comments
 (0)