Skip to content

Commit

Permalink
Add change event
Browse files Browse the repository at this point in the history
  • Loading branch information
hansottowirtz committed Sep 22, 2023
1 parent 2ce82e7 commit e265bec
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 2 deletions.
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,32 @@ import { ForkLeafDoneTracker } from "react-done-tracker";
</ForkLeafDoneTracker>
```
## Change event
In certain situations, it's useful to know when the children of a certain component have changed, e.g. when you want to screenshot those components after a change. On first load, you can wait for a `done` event. But when the children change in a non-async way, there will not be a second `done` event.
Because of that, you can trigger the `change` event if you want a parent component to know that the children have changed.
```tsx
// child
useEffect(() => {
doneTracker.signalChange();
}, [doneTracker, dep]);

// parent
useDoneTrackerSubscription(doneTracker, {
change: () => console.log("children have changed")
});
```
As a shorthand, you can use `useSignalChange`, which will create a new done tracker:
```tsx
useSignalChange("Dep watcher", [dep]);
```
The `change` event is not part of the "core" of this library. It was added because it's commonly needed.
## Caveats
### Slow hooks
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-done-tracker",
"version": "0.0.14",
"version": "0.0.15-beta.0",
"description": "Keep track of when your React tree is done loading",
"type": "module",
"main": "./dist/index.js",
Expand Down
10 changes: 10 additions & 0 deletions src/base-done-tracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export class BaseDoneTracker
abortListeners: DoneTrackerListener<"abort">[] = [];
errorListeners: DoneTrackerListener<"error">[] = [];
resetListeners: DoneTrackerListener<"reset">[] = [];
changeListeners: DoneTrackerListener<"change">[] = [];

addEventListener: DoneTracker["addEventListener"] = (event, listener) => {
if (event === "done") {
Expand All @@ -21,6 +22,8 @@ export class BaseDoneTracker
this.errorListeners.push(listener as any);
} else if (event === "reset") {
this.resetListeners.push(listener as any);
} else if (event === "change") {
this.changeListeners.push(listener as any);
}
};

Expand All @@ -45,6 +48,11 @@ export class BaseDoneTracker
this.resetListeners.indexOf(listener as any),
1
);
} else if (event === "change") {
this.changeListeners.splice(
this.changeListeners.indexOf(listener as any),
1
);
}
};

Expand All @@ -60,6 +68,8 @@ export class BaseDoneTracker
this.errorListeners.forEach((fn) => fn(arg as any));
} else if (event === "reset") {
this.resetListeners.forEach((fn) => fn(arg as any));
} else if (event === "change") {
this.changeListeners.forEach((fn) => fn(arg as any));
}
}
}
3 changes: 2 additions & 1 deletion src/done-tracker-interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ export interface DoneTrackerEventMap {
"done": [],
"abort": [],
"error": [any, DoneTracker],
"reset": []
"reset": [],
"change": [],
}

export type DoneTrackerListener<K extends keyof DoneTrackerEventMap> = (data: DoneTrackerEventMap[K]) => any
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export * from './visualize-wrapper';
export * from './hooks-util';
export * from './slow-hooks-util';
export * from './use-done-tracker-raw';
export * from './use-signal-change';
export * from './components/TrackDone';
export * from './components/ImperativeTrackDone';
export * from './components/ForkLeafDoneTracker';
Expand Down
9 changes: 9 additions & 0 deletions src/leaf-done-tracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,15 @@ export class LeafDoneTracker extends BaseDoneTracker implements DoneTracker {
this.dispatchEvent("error", err, this);
};

signalChange = () => {
if (this.aborted) {
warn("Already aborted, can't signal change", this.id);
return;
}
log("🌀 Signaling changed", this.id, "after");
this.dispatchEvent("change");
};

reset = () => {
if (this.aborted) {
warn("Already aborted, can't repend", this.id);
Expand Down
4 changes: 4 additions & 0 deletions src/node-done-tracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ export class NodeDoneTracker extends BaseDoneTracker implements DoneTracker {
debug("Child of", this.id, "resetted");
this.reset();
});
child.addEventListener("change", () => {
debug("Child of", this.id, "changed");
this.dispatchEvent("change");
});

if (child.done) {
debug("Child was already done when added", child.id);
Expand Down
9 changes: 9 additions & 0 deletions src/use-done-tracker-subscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ export const useDoneTrackerSubscription = (
done,
error,
pending,
change,
}: {
done?: () => void;
error?: (err: any, source: DoneTracker) => void;
pending?: () => void;
change?: () => void;
}
) => {
useEffect(() => {
Expand Down Expand Up @@ -58,4 +60,11 @@ export const useDoneTrackerSubscription = (
doneTracker.addEventListener("reset", fn);
return () => doneTracker.removeEventListener("reset", fn);
}, [doneTracker, pending]);

useEffect(() => {
if (!change) return;
const fn = () => change();
doneTracker.addEventListener("change", fn);
return () => doneTracker.removeEventListener("change", fn);
}, [doneTracker, change]);
};
11 changes: 11 additions & 0 deletions src/use-signal-change.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { useEffect } from "react";
import { useDoneTracker } from "./use-done-tracker";

export function useSignalChange(name: string, deps: any[]) {
const dt = useDoneTracker({
name,
done: true,
});
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => dt.signalChange(), [dt, ...deps]);
}

1 comment on commit e265bec

@vercel
Copy link

@vercel vercel bot commented on e265bec Sep 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.