電子冒険:エピソード14:反応する


前のエピソードでは、私はSvelte +ロールアップフロントエンドと電子プロジェクトを設定する方法を示した.今回は、我々は反応+ webpackと同じことをします.
そして再び、我々は最初に反応アプリを作成し、それを第二のステップとして電子を接続します周りの他の方法ではない.

反応アプリの作成


我々は、新しい反応アプリを作成することによって、通常の方法を起動し、必要なすべてのクラップを削除します.
実際には、デフォルトのテンプレートには、あまり必要ない必要があります.I'm going to use another template .
$ npx create-react-app episode-14-react --use-npm --template ready
あなたが反応しているならば、あなたはすでに大好きなテンプレートを持っているかもしれません、そして、あなたは代わりにそれを使うことができます.彼らのすべては、電子だけでうまく働きます.

無効にするブラウザの自動オープン


私たちは一つのことをする必要があります.反応するときに起動するブラウザのウィンドウを開くの迷惑な習慣があります-しかし、我々はブラウザのアプリをやっていない!
だから編集package.json 置換start 行:
"start": "BROWSER=none react-scripts start",

電子を加える


前のように、ここで必要な特別な手順はありません.
$ npm i --save-dev electron

バックエンドスクリプトインデックスを追加します。js


我々は既存のファイルを取ることができる、ちょうど私たちのdevサーバーでそれを指す.我々はアプリをパッケージ化するときに我々はそれがどの環境にあるかを認識する必要がありますし、そのURLをポイントしたり、生成されたファイルで、それに基づいて.
Svelteバージョンの唯一の違いは、デフォルトのポート番号です.
let { app, BrowserWindow } = require("electron")

function createWindow() {
  let win = new BrowserWindow({
    webPreferences: {
      preload: `${__dirname}/preload.js`,
    },
  })
  win.maximize()
  win.loadURL("http://localhost:3000/")
}

app.on("ready", createWindow)

app.on("window-all-closed", () => {
  app.quit()
})

preloadスクリプトプリロードを加えます。js


私たちはどんな変更もする必要がないので、前のエピソードから直接それを取ってください:
let child_process = require("child_process")
let { contextBridge } = require("electron")

let runCommand = (command) => {
  return child_process.execSync(command).toString().trim()
}

contextBridge.exposeInMainWorld(
  "api", { runCommand }
)

カスタマイズパブリック/インデックス。HTMLとsrc / indexjs


私はタイトルを変えるつもりです、テンプレートから来ているものは彼らがそうであるほど十分です.

src / indexCSS


SvelteはCSS組み込みをスコープしたので、私はそれを使用しました.反応はそのためにパッケージを持っていますが、それが組み込まれていないので、私はちょうど私たちがエピソード10で以前に使用したものとほとんど同じであるグローバルCSSファイルをここで使用します.
内容は以下の通りです:
body {
  background-color: #444;
  color: #fff;
  font-family: monospace;
}

.input-line {
  display: flex;
  gap: 0.5rem;
}

.input-line > * {
  flex: 1;
}

.input-line > .prompt {
  flex: 0;
}

.output {
  padding-bottom: 0.5rem;
}

.input {
  color: #ffa;
}

.output {
  color: #afa;
  white-space: pre;
}

form {
  display: flex;
}

input {
  flex: 1;
  font-family: inherit;
  background-color: inherit;
  color: inherit;
  border: none;
}

メインコンポーネントsrc / app。js


私たちはちょうど2つのコンポーネントをインポートし、それらを使用します.簡単にするために、CommandInput コンポーネント、ここではエクスポートしませんでした.
アプリを使用するwindow.api.runCommand これはpreloadスクリプトが起動する前に作成されたものです.ASrunCommand 同期され、それは本当に私たちの反応アプリを混乱させることができます.我々は、後のエピソードでそれを修正します.
import React from "react"
import CommandInput from "./CommandInput"
import HistoryEntry from "./HistoryEntry"

export default (props) => {
  let [history, setHistory] = React.useState([])

  let onsubmit = (command) => {
    let output = window.api.runCommand(command)
    setHistory([...history, { command, output }])
  }

  return (
    <>
      <h1>React Terminal App</h1>
      { history.map(({command, output}, index) => (
        <HistoryEntry key={index} command={command} output={output} />
      ))}
      <CommandInput onsubmit={onsubmit} />
    </>
  )
}

歴史エントリコンポーネントsrc / historyエントリ。js


それは完全に受動的です、ちょうど2つの渡された小道具が表示されます:
import React from "react"

export default ({command, output}) => {
  return <>
    <div className='input-line'>
      <span className='prompt'>$</span>
      <span className='input'>{command}</span>
    </div>
    <div className='output'>{output}</div>
  </>
}

コマンド入力コンポーネントsrc / command入力。js


これは、ローカルの状態でコマンドを保持し、ユーザーが送信するときにコールバックのみです.
import React from "react"

export default ({ onsubmit }) => {
  let [command, setCommand] = React.useState("")

  let submit = (e) => {
    e.preventDefault()
    onsubmit(command)
    setCommand("")
  }

  return <div className="input-line">
    <span className="prompt">$</span>
    <form onSubmit={submit}>
      <input type="text" autoFocus value={command} onChange={(e) => setCommand(e.target.value)} />
    </form>
  </div >
}

結果


結果は以下の通りです.

これは、Svelteバージョンより少し難しくありませんでした.ほとんどすべての現実世界の反応アプリはredux、immer、スタイルのコンポーネントのような余分な反応のアドオンの長いリストを使用しているので、それらのほとんどは、電子とだけで、あなたの心のコンテンツにカスタマイズするだけで動作します.
次のエピソードでは、バックエンドのasyncを作るので、スローコマンドはフロントエンド全体を凍結しません.
いつものように.all the code for the episode is here .