I am testing a bit of code to count rerenders.
This one does not work as I am passing <MyComponent>
as a child.
it("should get the same object when the parent rerenders", async () => {
jest.useFakeTimers();
const callback = jest.fn();
let renderCount = 0;
let x = 0;
function MyComponent() {
const random = Math.random();
const myRef = useRef({ random })
if (x === 0) {
x = myRef.current.random
}
++renderCount;
callback();
return (<div data-testid="test">{JSON.stringify(myRef.current)}</div>);
}
function MyStateComponent({ children }: PropsWithChildren<{}>) {
const forceUpdate = useReducer(() => ({}), {})[1] as () => void
useEffect(() => {
(async function asyncEffect() {
await delay(10000);
forceUpdate()
})()
}, [])
return (<>{children}</>);
}
const { getByTestId } = render(<MyStateComponent><MyComponent /></MyStateComponent>)
expect(getByTestId("test").textContent).toEqual(JSON.stringify({ random: x }));
expect(renderCount).toEqual(1);
expect(callback).toBeCalledTimes(1);
jest.runAllTimers();
await waitFor(() => {
expect(callback).toBeCalledTimes(2);
expect(getByTestId("test").textContent).toEqual(JSON.stringify({ random: x }));
expect(renderCount).toEqual(2);
});
})
However, this works but I embed <MyComponent />
into the component.
it("should get the same object when the parent rerenders with children", async () => {
jest.useFakeTimers();
const callback = jest.fn();
let renderCount = 0;
let x = 0;
function MyComponent() {
const random = Math.random();
const myRef = useRef({ random })
if (x === 0) {
x = myRef.current.random
}
++renderCount;
callback();
return (<div data-testid="test">{JSON.stringify(myRef.current)}</div>);
}
function MyStateComponent({ children }: PropsWithChildren<{}>) {
const forceUpdate = useReducer(() => ({}), {})[1] as () => void
useEffect(() => {
(async function asyncEffect() {
await delay(10000);
forceUpdate()
})()
}, [])
return (<MyComponent />);
}
const { getByTestId } = render(<MyStateComponent />)
expect(getByTestId("test").textContent).toEqual(JSON.stringify({ random: x }));
expect(renderCount).toEqual(1);
expect(callback).toBeCalledTimes(1);
jest.runAllTimers();
await waitFor(() => {
expect(callback).toBeCalledTimes(2);
expect(getByTestId("test").textContent).toEqual(JSON.stringify({ random: x }));
expect(renderCount).toEqual(2);
});
})
Since MyComponent
is determined to be a Pure functional component and it has no state to speak of, I presume React memoizes it automatically. To get around that and force a re-render the component needs part of itself to change, eg a context.
import { createContext, PropsWithChildren, useContext, useEffect, useReducer } from "react";
import { delay } from "./delay";
type IRendering = {}
const RenderingContext = createContext<IRendering>({})
/**
* This is a component that rerenders after a short delay
*/
export function RerenderingProvider({ children }: PropsWithChildren<{}>): JSX.Element {
const forceUpdate = useReducer(() => ({}), {})[1] as () => void
useEffect(() => {
(async function asyncEffect() {
await delay(10000);
forceUpdate();
})()
}, [])
return (<RenderingContext.Provider value={{}}>{children}</RenderingContext.Provider>);
}
export function useRerendering(): IRendering {
return useContext(RenderingContext);
}
With the following test...
it("should get the same object when the parent rerenders using component, but the component will rerender as context has changed", async () => {
jest.useFakeTimers();
const callback = jest.fn();
let x = 0;
function MyComponent() {
const _ignored = useRerendering();
const random = Math.random();
const myRef = useRef({ random })
if (x === 0) {
x = myRef.current.random
}
callback();
return (<>
<div data-testid="test">{JSON.stringify(myRef.current)}</div>
<div data-testid="random">{JSON.stringify(random)}</div>
</>);
}
const { getByTestId } = render(<RerenderingProvider><MyComponent /></RerenderingProvider>)
expect(getByTestId("test").textContent).toEqual(JSON.stringify({ random: x }));
expect(callback).toBeCalledTimes(1);
jest.runAllTimers();
await waitFor(() => {
expect(getByTestId("test").textContent).toEqual(JSON.stringify({ random: x }));
expect(callback).toBeCalledTimes(2);
});
})
I put up my scenario here... https://github.com/trajano/react-hooks-tests
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.