Skip to content
On this page

React

在本指南中,您将配置您的插件以使用 React。假设您已经拥有一个使用 custom view 的插件,并且想使用 React 来改写它。

虽然您并不需要使用单独的框架来开发一个插件,以下是您想使用 React 的几点原因:

  • 您有使用 React 的经验,并且想使用熟悉的技术。
  • 您想在插件中重复使用现有的 React 组件。
  • 您的插件需要复杂的状态管理,或者有使用常规 HTML element 无法实现的其他功能。

配置您的插件

  1. 将 React 添加到依赖中:
bash
npm install react react-dom
  1. 添加 React 的类型声明:
bash
npm install --save-dev @types/react @types/react-dom
  1. tsconfig.jsoncompilerOptions 对象中开启 JSX 支持:
ts
{
  "compilerOptions": {
    "jsx": "react"
  }
}

创建 React 组件

在插件的根目录下创建名为 ReactView.tsx 的文件,文件内容如下:

tsx
import * as React from "react";

export const ReactView = () => {
  return <h4>Hello, React!</h4>;
};

挂载 React 组件

要想使用 React 组件,需要在一个 HTML element 中挂载它。下例中将 ReactView 组件挂载到了 this.containerEl.children[1] 元素上:

tsx
import { ItemView, WorkspaceLeaf } from "obsidian";
import * as React from "react";
import * as ReactDOM from "react-dom";
import { ReactView } from "./ReactView";
import { createRoot } from "react-dom/client";

const VIEW_TYPE_EXAMPLE = "example-view";

class ExampleView extends ItemView {
  constructor(leaf: WorkspaceLeaf) {
    super(leaf);
  }

  getViewType() {
    return VIEW_TYPE_EXAMPLE;
  }

  getDisplayText() {
    return "Example view";
  }

  async onOpen() {
    const root = createRoot(this.containerEl.children[1]);
    root.render(
      <React.StrictMode>
        <ReactView />,
      </React.StrictMode>
    );
  }

  async onClose() {
    ReactDOM.unmountComponentAtNode(this.containerEl.children[1]);
  }
}

想要获取更多关于 ReactDOM.render() 以及 ReactDOM.unmountComponentAtNode() 的信息,可以去查阅 ReactDOM 这篇文档。

您可以将您的 React 组件挂载到任意 HTMLElement 上,可以看 status bar items 这个示例。当您使用完组件后请调用ReactDOM.unmountComponentAtNode() 方法确保组件被彻底移除。

创建应用上下文

如果您想从 React 组件中获取到 App 对象,您需要将其作为依赖传递。随着插件的迭代更新,尽管您在很少的几个地方使用了 App 对象,它也会在整个组件树中被传递。

还有一个选择就是给应用创建一个 React 上下文,使得 App 变成全局对象以便在 React 视图中的所有组件都可以获取到它。

  1. 使用 React.createContext() 去创建应用上下文
tsx
import * as React from "react";
import { App } from 'obsidian';

export const AppContext = React.createContext<App>(undefined);
  1. 用上下文提供者包装ReactView并将应用作为值传递
tsx
const root = createRoot(this.containerEl.children[1]);
root.render(
  <AppContext.Provider value={this.app}>
    <ReactView />
  </AppContext.Provider>,
  this.containerEl.children[1]
);
  1. 创建自定义钩子以便在组件中更方便的使用上下文。
tsx
import { AppContext } from "./context";

export const useApp = (): App | undefined => {
  return React.useContext(AppContext);
};
  1. ReactView 中的任意 React 组件中使用钩子函数以获取 app。
tsx
import * as React from "react";
import { useApp } from "./hooks";

export const ReactView = () => {
  const { vault } = useApp();

  return <h4>{vault.getName()}</h4>;
};

要想获取更多信息,可以查阅 React 文档中的 Context and Building Your Own Hooks