์ด ๊ฐ์ด๋์์๋ React๋ฅผ ์ฌ์ฉํ๋๋ก ํ๋ฌ๊ทธ์ธ์ ์ค์ ํฉ๋๋ค. React๋ฅผ ์ฌ์ฉํ๋๋ก ๋ณํํ๋ ค๋ ์ฌ์ฉ์ ์ ์ ๋ทฐ๊ฐ ์ด๋ฏธ ์๋ ํ๋ฌ๊ทธ์ธ์ ๊ฐ์ง๊ณ ์๋ค๊ณ ๊ฐ์ ํฉ๋๋ค.
ํ๋ฌ๊ทธ์ธ์ ๋น๋ํ๊ธฐ ์ํด ๋ณ๋์ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ ํ์๋ ์์ง๋ง, React๋ฅผ ์ฌ์ฉํ๋ ค๋ ๋ช ๊ฐ์ง ์ด์ ๊ฐ ์์ต๋๋ค:
- React์ ๋ํ ๊ธฐ์กด ๊ฒฝํ์ด ์๊ณ ์ต์ํ ๊ธฐ์ ์ ์ฌ์ฉํ๊ณ ์ถ์ ๋.
- ํ๋ฌ๊ทธ์ธ์์ ์ฌ์ฌ์ฉํ๊ณ ์ถ์ ๊ธฐ์กด React ์ปดํฌ๋ํธ๊ฐ ์์ ๋.
- ํ๋ฌ๊ทธ์ธ์ ๋ณต์กํ ์ํ ๊ด๋ฆฌ๋ ์ผ๋ฐ์ ์ธ HTML elements๋ก ๊ตฌํํ๊ธฐ ๋ฒ๊ฑฐ๋ก์ด ๋ค๋ฅธ ๊ธฐ๋ฅ์ด ํ์ํ ๋.
ํ๋ฌ๊ทธ์ธ ์ค์ ํ๊ธฐ
-
ํ๋ฌ๊ทธ์ธ ์ข ์์ฑ์ React๋ฅผ ์ถ๊ฐํฉ๋๋ค:
npm install react react-dom
-
React์ ๋ํ ํ์ ์ ์๋ฅผ ์ถ๊ฐํฉ๋๋ค:
npm install --save-dev @types/react @types/react-dom
-
tsconfig.json
์compilerOptions
๊ฐ์ฒด์์ JSX ์ง์์ ํ์ฑํํฉ๋๋ค:{ "compilerOptions": { "jsx": "react-jsx" } }
React ์ปดํฌ๋ํธ ์์ฑํ๊ธฐ
ํ๋ฌ๊ทธ์ธ ๋ฃจํธ ๋๋ ํ ๋ฆฌ์ ReactView.tsx
๋ผ๋ ์ ํ์ผ์ ๋ง๋ค๊ณ ๋ค์ ๋ด์ฉ์ ์ถ๊ฐํฉ๋๋ค:
export const ReactView = () => {
return <h4>Hello, React!</h4>;
};
React ์ปดํฌ๋ํธ ๋ง์ดํธํ๊ธฐ
React ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด HTML ์์์ ๋ง์ดํธํด์ผ ํฉ๋๋ค. ๋ค์ ์์ ๋ ReactView
์ปดํฌ๋ํธ๋ฅผ this.contentEl
์์์ ๋ง์ดํธํฉ๋๋ค:
import { StrictMode } from 'react';
import { ItemView, WorkspaceLeaf } from 'obsidian';
import { Root, createRoot } from 'react-dom/client';
import { ReactView } from './ReactView';
const VIEW_TYPE_EXAMPLE = 'example-view';
class ExampleView extends ItemView {
root: Root | null = null;
constructor(leaf: WorkspaceLeaf) {
super(leaf);
}
getViewType() {
return VIEW_TYPE_EXAMPLE;
}
getDisplayText() {
return 'Example view';
}
async onOpen() {
this.root = createRoot(this.contentEl);
this.root.render(
<StrictMode>
<ReactView />,
</StrictMode>,
);
}
async onClose() {
this.root?.unmount();
}
}
createRoot
๋ฐ unmount()
์ ๋ํ ์์ธํ ๋ด์ฉ์ ReactDOM ๋ฌธ์๋ฅผ ์ฐธ์กฐํ์ธ์.
React ์ปดํฌ๋ํธ๋ฅผ ์ํ ํ์์ค ํญ๋ชฉ๊ณผ ๊ฐ์ ๋ชจ๋ HTMLElement
์ ๋ง์ดํธํ ์ ์์ต๋๋ค. ์์
์ด ๋๋๋ฉด this.root.unmount()
๋ฅผ ํธ์ถํ์ฌ ์ ๋๋ก ์ ๋ฆฌํด์ผ ํฉ๋๋ค.
App ์ปจํ ์คํธ ์์ฑํ๊ธฐ
React ์ปดํฌ๋ํธ ์ค ํ๋์์ App ๊ฐ์ฒด์ ์ ๊ทผํ๋ ค๋ฉด ์ด๋ฅผ ์ข
์์ฑ์ผ๋ก ์ ๋ฌํด์ผ ํฉ๋๋ค. ํ๋ฌ๊ทธ์ธ์ด ์ปค์ง๋ฉด์ App
๊ฐ์ฒด๋ฅผ ๋ช ๊ตฐ๋ฐ์์๋ง ์ฌ์ฉํ๋๋ผ๋ ์ ์ฒด ์ปดํฌ๋ํธ ํธ๋ฆฌ๋ฅผ ํตํด ์ ๋ฌํ๊ธฐ ์์ํฉ๋๋ค.
๋ ๋ค๋ฅธ ๋์์ ์ฑ์ ๋ํ React ์ปจํ ์คํธ๋ฅผ ๋ง๋ค์ด React ๋ทฐ ๋ด๋ถ์ ๋ชจ๋ ์ปดํฌ๋ํธ์์ ์ ์ญ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๋๋ก ํ๋ ๊ฒ์ ๋๋ค.
-
createContext()
๋ฅผ ์ฌ์ฉํ์ฌ ์ ์ฑ ์ปจํ ์คํธ๋ฅผ ๋ง๋ญ๋๋ค.context.ts import { createContext } from 'react'; import { App } from 'obsidian'; export const AppContext = createContext<App | undefined>(undefined);
-
ReactView
๋ฅผ ์ปจํ ์คํธ ์ ๊ณต์๋ก ๊ฐ์ธ๊ณ ์ฑ์ ๊ฐ์ผ๋ก ์ ๋ฌํฉ๋๋ค.view.tsx this.root = createRoot(this.contentEl); this.root.render( <AppContext.Provider value={this.app}> <ReactView /> </AppContext.Provider> );
-
์ปดํฌ๋ํธ์์ ์ปจํ ์คํธ๋ฅผ ๋ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๋๋ก ์ฌ์ฉ์ ์ ์ ํ ์ ๋ง๋ญ๋๋ค.
hooks.ts import { useContext } from 'react'; import { AppContext } from './context'; export const useApp = (): App | undefined => { return useContext(AppContext); };
-
ReactView
๋ด์ ๋ชจ๋ React ์ปดํฌ๋ํธ์์ ํ ์ ์ฌ์ฉํ์ฌ ์ฑ์ ์ ๊ทผํฉ๋๋ค.ReactView.tsx import { useApp } from './hooks'; export const ReactView = () => { const { vault } = useApp(); return <h4>{vault.getName()}</h4>; };
์์ธํ ๋ด์ฉ์ React ๋ฌธ์์ Passing Data Deeply with Context ๋ฐ Reusing Logic with Custom Hooks๋ฅผ ์ฐธ์กฐํ์ธ์.