Skip to content

Commit

Permalink
move instance.registerEventHandler from createInstance to `commit…
Browse files Browse the repository at this point in the history
…Mount` in the React reconciler host config
  • Loading branch information
malash committed Nov 26, 2023
1 parent b15124e commit e209252
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`works with ErrorBoundary: ErrorBoundary fallback 1`] = `
Object {
"meta": Object {
"children": Array [
Object {
"gojiId": 4,
"text": "fallback",
"type": "GOJI_TYPE_TEXT",
},
],
"gojiId": 1,
"props": Object {},
"type": "GOJI_VIRTUAL_ROOT",
},
}
`;

exports[`works with ErrorBoundary: all components unmount 1`] = `
Object {
"meta": Object {
"children": Array [],
"gojiId": 1,
"props": Object {},
"type": "GOJI_VIRTUAL_ROOT",
},
}
`;

exports[`works with ErrorBoundary: test view showing 1`] = `
Object {
"meta": Object {
"children": Array [
Object {
"children": Array [
Object {
"gojiId": 5,
"text": "test",
"type": "GOJI_TYPE_TEXT",
},
],
"gojiId": 6,
"props": Object {},
"simplifiedId": 0,
"type": "view",
},
],
"gojiId": 1,
"props": Object {},
"type": "GOJI_VIRTUAL_ROOT",
},
}
`;
112 changes: 112 additions & 0 deletions packages/core/src/reconciler/__tests__/commitMount.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import React, { useEffect, useState } from 'react';
import { View } from '../../../dist/cjs';
import { gojiEvents } from '../../events';
import { render, RenderResult } from '../../__tests__/helpers';
import { act } from '../../testUtils';

jest.useFakeTimers();

jest.mock('../../events', () => ({
gojiEvents: {
registerEventHandler: jest.fn(),
unregisterEventHandler: jest.fn(),
},
}));

class ErrorBoundary extends React.Component {
public constructor(props) {
super(props);
}

public override state = { hasError: false };

public static getDerivedStateFromError() {
return { hasError: true };
}

public override render() {
const { hasError } = this.state;
if (hasError) {
setTimeout(() => {
this.setState({ hasError: false });
}, 3000);
// You can render any custom fallback UI
return 'fallback';
}

const { children } = this.props;
return children;
}
}

let shouldThrow = true;

const Broken = () => {
if (shouldThrow) {
shouldThrow = false;
throw new Error('broken error');
}

return null;
};

const App = () => {
const [show, setShow] = useState(true);
useEffect(() => {
setTimeout(() => {
setShow(false);
}, 6000);
}, []);

if (!show) {
return null;
}

return (
<ErrorBoundary>
<View>test</View>
<Broken />
</ErrorBoundary>
);
};

const renderApp = (): RenderResult => {
let wrapper: RenderResult;
act(() => {
wrapper = render(<App />);
});

// @ts-expect-error
return wrapper;
};

test('works with ErrorBoundary', () => {
// init
expect(gojiEvents.registerEventHandler).toBeCalledTimes(0);
expect(gojiEvents.unregisterEventHandler).toBeCalledTimes(0);

// first rendering, ErrorBoundary should show
const wrapper = renderApp();
expect(wrapper.getContainer()).toMatchSnapshot('ErrorBoundary fallback');
expect(gojiEvents.registerEventHandler).toBeCalledTimes(0); // `<View>test</View>` should not register event handler
expect(gojiEvents.unregisterEventHandler).toBeCalledTimes(0);

// second rendering, ErrorBoundary should hide after 3s
jest.advanceTimersByTime(3000);
expect(wrapper.getContainer()).toMatchSnapshot('test view showing');
expect(gojiEvents.registerEventHandler).toBeCalledTimes(1); // `<View>test</View>` should register event handler
expect(gojiEvents.unregisterEventHandler).toBeCalledTimes(0);

// third rendering, all components should be unmounted after 6s
jest.advanceTimersByTime(6000);
expect(wrapper.getContainer()).toMatchSnapshot('all components unmount');
expect(gojiEvents.registerEventHandler).toBeCalledTimes(1);
expect(gojiEvents.unregisterEventHandler).toBeCalledTimes(1); // `<View>test</View>` should unregister event handler
// id should same
expect(jest.mocked(gojiEvents.registerEventHandler).mock.calls[0][0]).toBe(
jest.mocked(gojiEvents.unregisterEventHandler).mock.calls[0][0],
);

// all timer done
expect(jest.getTimerCount()).toBe(0);
});
11 changes: 4 additions & 7 deletions packages/core/src/reconciler/hostConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,18 +97,15 @@ export const hostConfig: GojiHostConfig<
},

createInstance(type, newProps, rootContainerInstance) {
const instance = new ElementInstance(type, newProps, [], rootContainerInstance);
instance.registerEventHandler();

return instance;
return new ElementInstance(type, newProps, [], rootContainerInstance);
},

createTextInstance(text, rootContainerInstance) {
return new TextInstance(text, rootContainerInstance);
},

commitMount() {
// do nothing
commitMount(instance) {
instance.registerEventHandler();
},

commitUpdate(targetIns, updatePayload, type, oldProps, newProps) {
Expand All @@ -131,7 +128,7 @@ export const hostConfig: GojiHostConfig<
container.virtualRootElement.insertBefore(child, beforeChild);
},

finalizeInitialChildren: () => false,
finalizeInitialChildren: () => true,

appendChildToContainer(container, child) {
container.virtualRootElement.appendChild(child);
Expand Down

0 comments on commit e209252

Please sign in to comment.