前提
Alterlyの開発初期段階では、開発スピードを優先して jQuery を使って構築していました。
※サービスの詳細は Alterly公式サイト(https://alterly.net/) をご覧ください。
やりたいこと
サービスの本格運用が見えてきたことで、保守性や拡張性の観点から React を導入したいと考えました。
留意点
すでにベータ版が公開されているため、移行にともなって開発が大幅に遅延することや、サービスが破損することは極力避けたい状況でした。
段階的な移行の利点
① 初期コストを抑えられる
-
jQueryを一気にReactへ移行するには、大量のリファクタが必要ですが、段階的に進めれば影響範囲を限定できます。
-
チーム全体でReactの学習を並行して進めやすく、負担も少なくて済みます。
-
現在のjQueryコードが問題なく動作しているなら、壊さずに一部だけReact化することで改善可能です。
② Reactの利点を必要なところだけ活かせる
-
useState や props による状態管理、仮想DOMなどのReactの強みを限定的に活用できます。
-
コメント欄やタブUIなど、動的で複雑な部分だけReact化すれば、jQueryよりもシンプルに書けます。
-
UIをコンポーネント化できるため、再利用性が高く、別の画面でも使い回しやすくなります。
③ スケジュールに合わせて柔軟に進められる
-
「使用頻度の高い画面だけReact化」「時間があるときに少しずつ進める」など、現場の状況に合わせて移行可能です。
-
開発や運用を止めることなく、日々の業務と並行して改善を進められるのも大きな利点です。
④ トラブル時にも戻しやすい
-
Reactを限定的に導入しているため、問題が起きたらその部分だけjQueryに戻すことも簡単です。
-
jQueryとReactが共存できる構成なので、安全かつ段階的に移行できます。
移行前のコード例 (HTML + jQuery)
HTML
<div id="comments"></div>
<button id="send-btn">送信</button>
<script id="comment-template" type="text/template">
<div class="comment">
<p class="body"></p>
</div>
</script>
jQuery
const comments = [
{ id: 1, body: "これはコメント1です" },
{ id: 2, body: "これはコメント2です" },
];
function renderComments() {
const template = $('#comment-template').html();
$('#comments').empty();
comments.forEach((comment) => {
const $comment = $(template);
$comment.find('.body').text(comment.body);
$('#comments').append($comment);
});
}
$(function () {
renderComments();
$('#send-btn').on('click', () => {
alert('コメントを送信します');
});
});
おおまかには、以下のようなフォームをイメージしてください。
(実際には、CSSによるスタイル指定が必要となります)
送信するとコメントが追加されます。
移行後のコード例 (HTML+jQuery+React)
HTML
<div id="comment-root"></div>
jquery
<script>
const comments = [
{ id: 1, body: "これはコメント1です" },
{ id: 2, body: "これはコメント2です" }
];
$(function () {
const el = document.getElementById("comment-root");
if (el && window.renderComments) {
window.renderComments(el, comments);
}
});
</script>
react
①render.tsx(マウントスクリプト)
// src/render.tsx
import React from 'react';
import { createRoot } from 'react-dom/client';
import { CommentList } from './CommentList';
const roots = new Map<HTMLElement, ReturnType<typeof createRoot>>();
(window as any).renderComments = (el: HTMLElement, comments: any[]) => {
if (!el) return;
let root = roots.get(el);
if (!root) {
root = createRoot(el);
roots.set(el, root);
}
root.render(<CommentList comments={comments} />);
};
②CommentList.tsx(コンポーネント)
// src/CommentList.tsx
import React from 'react';
type Comment = {
id: number;
body: string;
};
type Props = {
comments: Comment[];
};
export const CommentList: React.FC<Props> = ({ comments }) => {
const handleSend = () => {
alert('コメントを送信します');
};
return (
<div>
<div className="comments">
{comments.map((c) => (
<div key={c.id} className="comment">
<p className="body">{c.body}</p>
</div>
))}
</div>
<button className="send-btn" onClick={handleSend}>
送信
</button>
</div>
);
};
所感
① 移行作業について
旧jQueryコードをChatGPTに投げることで、一定の精度でReactへの変換案が得られました。
ただし、最初から完全に意図通りに動くことは少なく、実際には調整やコード理解の時間が必要でした。
② 移行後の開発について
Reactに移行したことで、コードの構造が格段に整理されました。
また、useState や props を使った状態管理により、jQuery時代にありがちだった「フラグ地獄」から解放され、UIロジックも明確に。
その結果、開発効率や保守性も大きく向上しました。
③ 今後の開発について
今後は「まずjQueryで作って、あとからReactに移行する」といった流れは極力避けたいと考えています。
現在はAIの支援もあるため、最初から「この機能をReactで作りたい」とAIに指示して開発を進める方が、圧倒的に効率が良いと実感しています。
参考
・React公式:既存プロジェクトに React を追加する
https://ja.react.dev/learn/add-react-to-an-existing-project
・White Box技術部:TypeScriptでwindowにプロパティを追加するいくつかの方法
https://seri.hatenablog.com/entry/2020/01/24/152918
※簡略化のために、マウントスクリプトで「(window as any).」を用いる方法について参照しました。