Skip to content

Commit

Permalink
feat: migrate to typescript project reference
Browse files Browse the repository at this point in the history
  • Loading branch information
Aqours committed Nov 10, 2023
1 parent 57cb8bd commit 578b4e1
Show file tree
Hide file tree
Showing 60 changed files with 1,302 additions and 857 deletions.
1 change: 0 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
"rules": {
"no-undef": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/no-explicit-any": "off",

"@typescript-eslint/no-unused-vars": 1
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,8 @@ pip-log.txt

# Mac crap
.DS_Store

#################
## MISC
#################
.ts-build
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
**/.ts-build
**/dist
**/release
**/coverage
Expand Down
10 changes: 6 additions & 4 deletions apps/react-demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@
"license": "ISC",
"dependencies": {
"@apex/svg-project": "workspace:*",
"mobx": "6.9.0",
"mobx-react-lite": "3.4.3",
"mobx": "6.10.2",
"mobx-react-lite": "4.0.5",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"@types/react": "18.2.20",
"@types/react-dom": "18.2.7"
"@apex/webpack-config": "workspace:*",
"@types/react": "18.2.37",
"@types/react-dom": "18.2.15",
"webpack-cli": "5.1.4"
}
}
2 changes: 0 additions & 2 deletions apps/react-demo/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
<div id="app1"></div>
<hr>
<div id="app2"></div>
<hr>
<div id="app3"></div>
<script src="app.js"></script>
</body>
</html>
56 changes: 17 additions & 39 deletions apps/react-demo/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,26 @@
import './style/global.less';
import React from 'react';
import { createRoot, Root } from 'react-dom/client';
import { createRoot } from 'react-dom/client';
import { RootStore } from './store/root.store';
import { JetbrainsLogo } from '@apex/svg-project';
import { RootContext } from './context';
import { TimerView } from './component/mobx/Timer.View';
import { ThemeSwitchView, ThemeSwitchView2 } from './component/mobx/ThemeSwitch.View';
import { MobxThemeSwitch } from './component/mobx/MobxThemeSwitch';
import { MobxThemeSwitch2 } from './component/mobx/MobxThemeSwitch2';
import { Section } from './component/mobx/Section';

export class App {
root: Root;
rootStore: RootStore;
timer: number;
export function createReactApp(container: HTMLElement, node?: HTMLElement) {
const rootStore = new RootStore();
const root = createRoot(container);

constructor(
readonly container: HTMLElement,
readonly rate?: number,
readonly node?: HTMLElement,
) {
this.rootStore = new RootStore();
this.root = createRoot(container);
this.render();
this.startCount();
}
root.render(
<RootContext.Provider value={rootStore}>
<Section />
<Section />
<p style={{ width: 128 }} dangerouslySetInnerHTML={{ __html: JetbrainsLogo }} />
<MobxThemeSwitch />
<MobxThemeSwitch2 />
</RootContext.Provider>,
);

render() {
this.root.render(
<RootContext.Provider value={this.rootStore}>
<TimerView node={this.node} tip={this.rate === 1 || this.rate == null ? null : `${this.rate}x`} />
<p style={{ width: 128 }} dangerouslySetInnerHTML={{ __html: JetbrainsLogo }} />
<ThemeSwitchView />
<ThemeSwitchView2 />
</RootContext.Provider>,
);
}

startCount() {
this.timer = window.setInterval(() => this.rootStore.timerStore.increaseTimer(this.rate), 1000);
}

dispose() {
clearInterval(this.timer);
this.root.unmount();
this.root = null;
this.rootStore = null;
this.timer = null;
}
return () => root.unmount();
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react';
import { useEffect, useMemo, useState } from 'react';

/**
* @desc Pure React Component (Can reuse in other project)
Expand All @@ -7,15 +7,20 @@ import { useEffect, useState } from 'react';
* The useEffect hook is used to execute a timer that increments the count variable every second.
* The component renders a paragraph element displaying the current value of count.
*/
export const CounterAtom = () => {
export const Counter = () => {
const initValue = useMemo(() => Math.round(Math.random() * 10), []);
// Local state (React)
const [count, setCount] = useState(0);
const [count, setCount] = useState(initValue);

// Local counter
useEffect(() => {
const timerId = setInterval(() => setCount((n) => n + 1), 1000);
return () => clearInterval(timerId);
}, []);

return <p>Local counter: {count} tick</p>;
return (
<p>
Initial value: {initValue}. Local counter: {count} tick (Component Level)
</p>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { memo } from 'react';
* @desc Pure React Component (Can reuse in other project)
* @desc React memo example
*/
export const HeadingAtom = memo(() => {
export const Heading = memo(() => {
// Check console message in devtool
console.log('[debug] Every component should be memoized and log once');
return <h2>Hello world! (Static Content)</h2>;
Expand Down
17 changes: 17 additions & 0 deletions apps/react-demo/src/component/atom/Submit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
interface ISubmitProps {
submitted: boolean;
onClick: () => void;
}

/**
* @desc Pure React Component (Can reuse in other project)
*/
export function Submit({ submitted, onClick }: ISubmitProps) {
return (
<p>
<button onClick={onClick} disabled={submitted}>
Submit Button (App Level)
</button>
</p>
);
}
43 changes: 0 additions & 43 deletions apps/react-demo/src/component/atom/Timer.Atom.tsx

This file was deleted.

18 changes: 18 additions & 0 deletions apps/react-demo/src/component/mobx/MobxSubmit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useStore } from '../../context';
import { observer } from 'mobx-react-lite';
import { Submit } from '../atom/Submit';
import { useCallback } from 'react';

/**
* @desc View with Store (Cannot reuse without same store)
*/
export const MobxSubmit = observer(() => {
// App store (Mobx)
const { submitStore } = useStore();
const onClick = useCallback(() => {
submitStore.toggle();
setTimeout(() => submitStore.toggle(), 3000);
}, []);

return <Submit submitted={submitStore.submitted} onClick={onClick} />;
});
15 changes: 15 additions & 0 deletions apps/react-demo/src/component/mobx/MobxThemeSwitch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { observer } from 'mobx-react-lite';
import { useEffect } from 'react';
import { themeStore } from '../../store/global/theme.store';

export const MobxThemeSwitch = observer(() => {
useEffect(() => {
document.body.dataset.theme = themeStore.theme;
}, [themeStore.theme]);

return (
<p>
<button onClick={() => themeStore.toggle()}>Switch Theme (Global Level: import global store)</button>
</p>
);
});
23 changes: 23 additions & 0 deletions apps/react-demo/src/component/mobx/MobxThemeSwitch2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { observer } from 'mobx-react-lite';
import { useStore } from '../../context';
import { useEffect } from 'react';

/**
* @desc Only demo
*/
export const MobxThemeSwitch2 = observer(() => {
/**
* Use ReactContext instead of import variable.
*/
const { themeStore } = useStore();

useEffect(() => {
document.body.dataset.theme = themeStore.theme;
}, [themeStore.theme]);

return (
<p>
<button onClick={() => themeStore.toggle()}>Switch Theme2 (Global Level: useContext)</button>
</p>
);
});
23 changes: 23 additions & 0 deletions apps/react-demo/src/component/mobx/Section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Counter } from '../atom/Counter';
import { Heading } from '../atom/Heading';
import { MobxSubmit } from './MobxSubmit';

/**
* @desc Should put it to page or section directory. Here is a demo.
*/
export const Section = () => {
return (
<>
{/* It's a memo component */}
<Heading />

{/* It's a pure react component */}
{/* DON'T USE THIS in Mobx, it's only a demo */}
{/* Wrap it with Mobx.observer if you want to use it in mobx environment */}
<Counter />

{/* Share application store */}
<MobxSubmit />
</>
);
};
25 changes: 0 additions & 25 deletions apps/react-demo/src/component/mobx/ThemeSwitch.View.tsx

This file was deleted.

18 changes: 0 additions & 18 deletions apps/react-demo/src/component/mobx/Timer.View.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion apps/react-demo/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ import { createContext, useContext } from 'react';
import { RootStore } from './store/root.store';

export const RootContext = createContext<RootStore | null>(null);
export const useStore = () => useContext(RootContext);
export const useStore = () => useContext(RootContext) as RootStore;
26 changes: 11 additions & 15 deletions apps/react-demo/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
import { App } from './app';
import { createReactApp } from './app';

function getCustomNode(text: string) {
const span = document.createElement('span');
span.textContent = text;
return span;
function getElementById(id: string) {
return document.getElementById(id) as HTMLElement;
}

const app1Container = document.getElementById('app1');
const app2Container = document.getElementById('app2');
const app3Container = document.getElementById('app3');
const app1Container = getElementById('app1');
const app2Container = getElementById('app2');

const app1 = new App(app1Container);
const app2 = new App(app2Container, 2);
const app3 = new App(app3Container, 3, getCustomNode('(app3)'));
const disposeApp1 = createReactApp(app1Container);
const disposeApp2 = createReactApp(app2Container);

setTimeout(() => {
app3.dispose();
console.log('[debug] app3 has been disposed');
disposeApp2();
console.log('[debug] app2 has been disposed');

setTimeout(() => {
new App(app3Container, 4, getCustomNode('(app3 with rate=4)'));
console.log('[debug] re-render app3 with rate=4');
createReactApp(app2Container);
console.log('[debug] re-render app2');
}, 2000);
}, 4000);
Loading

0 comments on commit 578b4e1

Please sign in to comment.