Reactの入力フォームを仮想ウインドウ化する

# Reactの入力フォームを仮想ウインドウ化する

![sc.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267629/59a7e5c4-6958-b969-dc56-aab376296f63.gif)

## ユーザ入力用のUIの位置決めが面倒くさい

　フロントエンドのUIを作る際、ユーザ入力を行うための場所をわざわざ作るのはそれなりに手間のかかる作業です。特に配置場所を作るのがそれなりに面倒です。今回はこれをできる限り簡単に解決する方法を解説していきたいと思います。

　こちらの記事でToDoを入力するためのアプリケーションを作ったので、その入力フォームを改造していきます。

　　[React-Reduxが難しい？ それは過去の話だ！ ～ ToDoアプリを最小限の労力で記述する ～](https://qiita.com/SoraKumo/items/be41bebdc5609770ac21)


　今回必要とするコンポーネント
　　　[https://www.npmjs.com/package/@jswf/react](https://www.npmjs.com/package/@jswf/react)

### インストールの方法

    npm -D i @jswf/react

## 仮想ウインドウを利用する上でやるべき事

フォームの該当箇所をJSWindowで囲む

```html
<JSWindow>～</JSWindow>
```

以上で入力フォームの仮想ウインドウ化は完了しました。お疲れ様です。

前回のプログラムを変更するとこんな感じです。

```tsx
function FormComponent() {
  const todoModule = useModule(TodoModule);
  return (
   <JSWindow>{/*←追加*/}
    <div style={{ textAlign: "center" }}>
      <div>
        <div>タイトル</div>
        <input
          style={{ width: "20em" }}
          value={todoModule.getState("input", "title")!}
          onChange={e => todoModule.setState(e.target.value, "input", "title")}
        />
        <div>説明</div>
        <textarea
          style={{ width: "20em", height: "5em" }}
          value={todoModule.getState("input", "desc")!}
          onChange={e => todoModule.setState(e.target.value, "input", "desc")}
        />
        <div>
          <button onClick={() => todoModule.addTodo()}>Todoを作成</button>
        </div>
      </div>
    </div>
   <JSWindow>{/*←追加*/}
  );
}
```

　足したのはJSWindowだけです。これによって、以下のように仮想ウインドウ上にコンテンツが表示されるようになりました。この仮想ウインドウはサイズが可変、移動、最大化、最小化の機能がデフォルトで付いています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267629/b19cb863-60cf-2fd0-0a00-43725b18d78a.png)

　この仮想ウインドウ、閉じるボタンが搭載されているので押したら消えます。そして二度とToDOを書き込むことは出来なくなるという自由が手に出来てしまいます。

　流石にそれでは困るので、閉じたウインドウを再び開けるようにします。

```tsx
interface TodoState {
  //入力中データの保持
  input: {
    title: string;
    desc: string;
  };
  //TODOリスト
  todos: {
    id: number;
    title: string;
    desc: string;
    done: boolean;
  }[];
  //TODOのID附番表index
  index: number;
  //ウインドウの状態
  windowState: WindowState; //<----- 追加
}
//初期値
protected static defaultState: TodoState = {
  todos: [],
  input: { title: "", desc: "" },
  index: 0,
  windowState: WindowState.HIDE //<----- 初期状態の追加
};

function FormComponent() {
  const todoModule = useModule(TodoModule);
  return (
    <>
      {/* ボタンの追加 */}
      <button
        onClick={()=>todoModule.setState({ WindowState: WindowState.NORMAL })}
      >
        ウインドウの表示
      </button>
      {/* タイトルとウインドウ状態設定を追加 */}
      <JSWindow title="ToDoの入力" windowState={todoModule.getState("WindowState")!}>
        <div style={{ textAlign: "center" }}>
          <div>
            <div>タイトル</div>
            <input
              style={{ width: "20em" }}
              value={todoModule.getState("input", "title")!}
              onChange={e =>
                todoModule.setState(e.target.value, "input", "title")
              }
            />
            <div>説明</div>
            <textarea
              style={{ width: "20em", height: "5em" }}
              value={todoModule.getState("input", "desc")!}
              onChange={e =>
                todoModule.setState(e.target.value, "input", "desc")
              }
            />
            <div>
              <button onClick={() => todoModule.addTodo()}>Todoを作成</button>
            </div>
          </div>
        </div>
      </JSWindow>
    </>
  );
}
```

　windowStateを設定すると、仮想ウインドウの状態を変更することが出来ます。ということで、ボタンを押したらステータスをNORMALに戻し再表示出来るようになりました。


## まとめ

　この仮想ウインドウコンポーネントは複数表示やネストも可能です。詳細な機能に関しては

　　[Reactで超簡単、タグで挟み込むだけの仮想ウインドウの実装](https://qiita.com/SoraKumo/items/c9157dc2f087a0da69bf)

　の記事で説明しています。