Facebook投稿支援アプリにReact/Vueは必要か (6)?
WebアプリやWebサービスを開発するのにフレームワークがどこまで必要なのかをシンプルなアプリを例にして考える企画を実施しています。 これまでに、HTMLファイルをベースとした実装例として、シンプルなHTMLとJavascript、jQuery、CDNをベースにしたReactとVueの実装例を紹介してきました。
前回の記事でまとめたように、ReactやVueを使う場合、「npm」を利用してReactやVueのプロジェクトを作成して開発した方が便利です。ReactやVueを利用した開発の殆どは、CDNではなく、「npm」が利用されています。この記事では、「npm」を利用したReactの実装例を紹介しています。
パッケージを管理する「npm」
Node.jsをインストールすると、合わせてインストールされるのが「npm」というパッケージ管理ツールです。このツールを利用すると、インターネット上で公開されているNode.js(Javascript)のパッケージを自分のWebアプリやサービスに取り込んで簡単に利用できます。
少し規模の大きなWebアプリやサービスの場合、そうした既存の公開されているパッケージを利用できるので開発の効率が向上します。
もちろん、CDN(Contents Delivery Network)で、HTMLファイルから読み込めばこうしたパッケージも利用できるのですが、規模が大きなアプリやサービスの場合、npmで取り込んでしまった方が便利です。
Node.jsは、オフィシャルサイトからダウンロードして簡単にインストールできます。
Reactのプロジェクトのテンプレートを作成
Reactのプロジェクトはnpmのパッケージの「create-react-app」というパッケージを利用すると簡単に作成できます。Reactで開発を行う場合、頻繁に利用するので、開発用のPCにどのフォルダからも利用できるようにインストールして置くと便利です。
$ npm install -g create-react-app
(*)MacやLinuxの場合、「sudo」をつける必要があります。(sudo install -g create-react-app)
このパッケージがインストールされていれば、以下のコマンドでReactのプロジェクトのテンプレートが作成できます。
$ npx create-react-app [プロジェクト名] --template typescript
(*)この連載ではTypescriptの利用を推奨しているため、Typescriptの設定でテンプレートのプロジェクトを作成しています。Javascriptで開発する場合は、「--template typescript」は不要です。
これで、「src/index.ts」と「src/app.tsx」のファイルを書き換えて、目的のアプリやサービスを作成します。
Facebook投稿支援アプリの場合は?
前回まで作成したFacebook投稿支援アプリの場合、メニューバーやコピーライトを覗いた主要部分は以下のような感じで実装できます。 今回は、「form.tsx」というファイルに以下のコードを保存して「app.tsx」から呼び出して利用するようにしてみました。
form.tsxの例です
import * as React from "react";
interface IProps {}
interface IState {
contents: string;
converted: boolean;
}
export default class MainForm extends React.Component<IProps, IState> {
private text: React.RefObject<HTMLTextAreaElement> = React.createRef<HTMLTextAreaElement>();
constructor(props: IProps) {
super(props);
this.state = {
contents: "",
converted: false,
};
}
clear(): void {
this.setState({
contents: "",
converted: false,
});
}
convert(): void {
let new_contents: string = "";
for (let i: number = 0; i < this.state.contents.length; i++) {
const c: string = this.state.contents[i];
if (c === "\n") {
new_contents = new_contents + c + String.fromCharCode(8203);
} else {
new_contents = new_contents + c;
}
}
this.setState({
contents: new_contents,
converted: true,
});
if (this.text.current) {
this.text.current.select();
document.execCommand("copy");
}
}
updateText(e: React.ChangeEvent<HTMLTextAreaElement>): void {
const value: string = e.target.value;
this.setState({
contents: value,
});
}
render(): JSX.Element {
return (
<React.Fragment>
<form className="form-group fb_form">
<textarea
className="form-control"
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) =>
this.updateText(e)
}
value={this.state.contents}
ref={this.text}
readOnly={this.state.converted}
></textarea>
<button
type="button"
className={
this.state.converted ? "btn btn-danger" : "btn btn-primary"
}
onClick={
this.state.converted ? () => this.clear() : () => this.convert()
}
>
{this.state.converted ? "クリア" : "変換"}
</button>
</form>
</React.Fragment>
);
}
}
これを、App.tsxから呼び出せば同じアプリが実現できます。
import React from "react";
import MainForm from "./form";
import "./App.css";
interface IProps {}
interface IState {}
function App():JSX.Element {
return (
<div className="App">
<nav className="navbar navbar-expand-md navbar-dark bg-dark">
<div className="container-fluid">
<a className="navbar-brand" href="/">
Facebook投稿ツール
</a>
</div>
</nav>
<MainForm/>
<div className="footer bg-dark">
<footer>
Copyright(c) 2021 by Silicon Valley Super Ware, all rights reserved.
</footer>
</div>
</div>
);
}
export default App;
メニューバーと、コピーライトはApp.tsxに記述しているので、別の表示でも共通で利用できます。例えば、このフォームの代わりに、原稿をファイルから読み込んだりする場合、ファイル選択の画面に切り替える場合、「MainForm」の部分を、置き換えれば、画面ごとにメニューバーやコピーライトを画面ごとに配置しなくても表示させることが可能です。
ページ数(表示画面数)が多いアプリやサービスを作る場合便利です。
ファイル選択画面の例
ファイル選択の画面の例です。
import * as React from "react";
interface IProps {
fileName: React.RefObject<HTMLInputElement>;
onChange: ((event: React.ChangeEvent<HTMLInputElement>) => void) | undefined;
}
interface IState {}
export default class SelectFile extends React.Component<IProps, IState> {
private fileField: React.RefObject<HTMLInputElement> = React.createRef<HTMLInputElement>();
fileSelectionEvent() {
if (this.fileField.current) {
this.fileField.current.click();
}
}
render() {
return (
<React.Fragment>
<div className="form-group">
<label>ファイル</label>
<input
className="form-control"
type="text"
ref={this.props.fileName}
placeholder="ファイルを選択してください"
readOnly
/>
<button
className="btn btn-primary"
onClick={() => this.fileSelectionEvent()}
>
選択
</button>
<input
className="hide"
type="file"
onChange={this.props.onChange}
ref={this.fileField}
/>
</div>
</React.Fragment>
);
}
}
このような、部品(Component)を作成して、「MainForm」と置き換えれば、ファイルの入力画面に切り替える事ができます。
このファイル選択画面では、選択ボタンを押した場合、イベント処理で、ファイルの入力フィールドにクリックのイベントを発生させてファイルの選択を行うようにしています。 ファイルが選択されたイベントは呼び出し元で処理するように、プロパティを受け取る形にしています。呼び出し元での処理で、ファイルの名前のフィールに選択されたファイルの名前をセットできるように、入力フィールドのリファレンスもプロパティとして受け取るようになっています。
ファイルの入力フィールドは、CSSで表示しないようにしています。
実際の実装では、これ以外にメニューバーにメニューを追加して、ファイル選択のメニューと、フォームを表示するメニューを追加して切り替えるようにします。 実装には、App.tsxでファイルから取り込んだ内容を保持するステートを管理したりする機能や、イベントの処理を追加する必要があります。
(或いは、React Routerを実装して切り替えるようにしても実装できます)
まとめ
npmを利用して、Reactのプロジェクトを作成して開発を行うと、多くお画面を切り替えて表示させたりする実装がより効率的にできるようになります。 1ページで完結するシンプルなアプリでも、将来的に機能を拡張したりするのが容易にできるので、長い目で考えた場合、CDNでHTMLページで作製するより、拡張性、保守性などが大幅に良くなります。
多くの場合、Webアプリやサービスとして実装する場合、保守や拡張を視野に入れて開発した方が有利です。