Open1

DjangoのテンプレートにReactコンポーネントを埋め込む

ねちょねちょ

Djangoで開発を行っているが、テンプレートで複雑なUIを実装するのが辛く、Reactを使いたい。
段階的に移行できると嬉しいので、既存のテンプレートにReactコンポーネントを埋め込む方法を考える。

やること

カウンター(数字と、クリックすると数字を増やすボタン)をコンポーネントとして実装する。
パス等は適宜読み替えること

React

viteプロジェクトの作成

公式のガイドを参考に作成する。テンプレートはreactを選択。https://vite.dev/guide/

コンポーネントの作成

適当に実装する

App.tsx
import { useState } from "react";

export function App(){
    const [count, setCount] = useState(0);
    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={() => setCount(count + 1)}>Increment</button>
        </div>
    );
}

レンダリングするためのtsx

main.tsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { App } from './App'

createRoot(document.getElementById('react_root')!).render(
  <StrictMode>
    <App/>
  </StrictMode>,
)

ビルド設定の変更

試しに変更してみたもの

vite.config.ts
export default defineConfig({
  plugins: [react()],
  build: {
    outDir: '../backend/example/static/react',
    emptyOutDir: true,
    rollupOptions: {
      input: {
        counter: resolve(__dirname, 'src/counter/main.tsx'),
      },
      output: {
        entryFileNames: '[name].js',
      }
    }
  }
})
  • build.outDir
    • 出力先ディレクトリ。djangoから読み込めればどこでも良いが、djangoのstatic内にした。
  • build.emptyOutDir
    • 出力先ディレクトリがviteプロジェクト外だと出力先を空にするときに警告が出るので、それを消すための設定。
  • rollupOptions.input
    • ビルド対象。複数のモジュールを作成したいならここに追加する。
  • rollupOptions.output.entryFileNames
    • デフォルトではビルドしたjsのファイル名にハッシュ値が付くが、
      Djangoのテンプレートから読み込むときに面倒なので、ビルドごとに名前が変わらないようにしてある

Django

ビルドしたものを読み込む

template.html
{% load static %}
<script type="module" src="{% static 'react/counter.js' %}"></script>

レンダリングのためのdivを追加

template.html
<body>
    <h1>カウンター</h1>
    <div id="react_root"></div>
</body>

できていないこと

  • テンプレートに渡されたcontextをReactコンポーネントに渡す
  • 出力先ディレクトリを分ける