Skip to content

Commit

Permalink
add useWhyDidYouUpdate hook
Browse files Browse the repository at this point in the history
  • Loading branch information
imbhargav5 committed Apr 29, 2023
1 parent a7e7083 commit b02c8ec
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 0 deletions.
19 changes: 19 additions & 0 deletions data/docs/useWhyDidYouUpdate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
id: useWhyDidYouUpdate
title: useWhyDidYouUpdate
sidebar_label: useWhyDidYouUpdate
---

## About

A hook that can track which value change caused a rerender

## Examples

```tsx
import {useWhyDidYouUpdate} from "rooks"
export default function App() {
useWhyDidYouUpdate();
return null
}
```
5 changes: 5 additions & 0 deletions data/hooks-list.json
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,11 @@
"description": "Video hook for react",
"category": "ui"
},
{
"name": "useWhyDidYouUpdate",
"description": "A hook that can track which value change caused a rerender",
"category": "misc"
},
{
"name": "useWillUnmount",
"description": "componentWillUnmount lifecycle as hook for React.",
Expand Down
86 changes: 86 additions & 0 deletions packages/rooks/src/__tests__/useWhyDidYouUpdate.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/**
* @jest-environment jsdom
*/
import React from "react";
import {
screen,
render,
act,
fireEvent,
cleanup,
} from "@testing-library/react";
import { useWhyDidYouUpdate } from "@/hooks/useWhyDidYouUpdate";
import { waitFor } from "@testing-library/react";
import { useCounter } from "..";

describe("useWhyDidYouUpdate", () => {
let TestComponent: React.FC<{
enableLogging?: boolean;
}>;
beforeEach(() => {
jest.spyOn(global.console, "log").mockImplementation(jest.fn);
});
beforeEach(() => {
TestComponent = ({ enableLogging = true }) => {
const { value, increment } = useCounter(0);
useWhyDidYouUpdate("TestComponent", { value }, enableLogging);
return <button onClick={increment}>Increment</button>;
};
});

afterEach(() => {
(console.log as jest.Mock).mockRestore();
cleanup();
});

it("should not log on initial render", () => {
expect.hasAssertions();

render(<TestComponent />);

expect(console.log).not.toHaveBeenCalled();
});

it("should log on prop updates", async () => {
expect.hasAssertions();

render(<TestComponent />);

const button = screen.getByRole("button");

act(() => {
fireEvent(
button,
new MouseEvent("click", {
bubbles: true,
cancelable: true,
})
);
});

await waitFor(() => {
expect(console.log).toHaveBeenCalledWith(
"[why-did-you-update]",
"TestComponent",
{ value: { from: 0, to: 1 } }
);
});
});

it("should not log when enableLogging is false", () => {
expect.hasAssertions();
render(<TestComponent enableLogging={false} />);
const button = screen.getByRole("button");
act(() => {
fireEvent(
button,
new MouseEvent("click", {
bubbles: true,
cancelable: true,
})
);
});

expect(console.log).not.toHaveBeenCalled();
});
});
42 changes: 42 additions & 0 deletions packages/rooks/src/hooks/useWhyDidYouUpdate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* useWhyDidYouUpdate
* @description A hook that can track which value change caused a rerender
* @see {@link https://rooks.vercel.app/docs/useWhyDidYouUpdate}
*/
import { useEffect, useRef } from "react";
import { useDidUpdate } from "./useDidUpdate";

export type PropsRecord = Record<string, unknown>;

export function useWhyDidYouUpdate(
componentName: string,
currentProps: PropsRecord,
enableLogging = true
) {
const previousProps = useRef<PropsRecord>({});
useDidUpdate(() => {
if (previousProps.current && enableLogging) {
const combinedKeys = Object.keys({
...previousProps.current,
...currentProps,
});
const changedProps: PropsRecord = {};
combinedKeys.forEach((key) => {
if (!Object.is(previousProps.current[key], currentProps[key])) {
changedProps[key] = {
from: previousProps.current[key],
to: currentProps[key],
};
}
});

if (Object.keys(changedProps).length) {
console.log("[why-did-you-update]", componentName, changedProps);
}
}
}, [currentProps, componentName, enableLogging]);

useEffect(() => {
previousProps.current = currentProps;
});
}
1 change: 1 addition & 0 deletions packages/rooks/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export { useUndoState } from "@/hooks/useUndoState";
export { useUndoRedoState } from "@/hooks/useUndoRedoState";
export { useVibrate } from "@/hooks/useVibrate";
export { useVideo } from "@/hooks/useVideo";
export { useWhyDidYouUpdate } from "@/hooks/useWhyDidYouUpdate";
export { useWillUnmount } from "@/hooks/useWillUnmount";
export { useWindowEventListener } from "@/hooks/useWindowEventListener";
export { useWindowScrollPosition } from "@/hooks/useWindowScrollPosition";
Expand Down

0 comments on commit b02c8ec

Please sign in to comment.