본문으로 바로가기

[Electron] electron react 서로 통신하기

category 공유/Electron 2022. 3. 21. 05:09

[Electron] electron react 서로 통신하기

react, electron 서로 통신하는 방법을 알아보도록 하겠습니다. 서로 데이터를 주고 받고, electron에서 fs와 같은 모듈을 사용해야지 electron을 사용하는 이유가 있겠죠? 아니면 그냥 웹으로 사용하면 되는 것을 굳이 desktop app으로 만들어 사용할 필요가 없습니다. 이번 게시글에서는 react와 electron 사이 데이터를 주고 받는 방법을 알아보도록 하겠습니다. 그리고 추가로 파일을 선택하여 해당 파일 명을 보여주는 작업도 해보겠습니다.

react, electron 통신하기

react와 electron 사이 데이터를 주고 받는 방법은 매우 간단합니다. ipcMain, ipcRenderer를 사용하면 됩니다. electron에서는 ipcMain, react에서는 ipcRenderer를 사용하면 됩니다. 해당 함수들을 사용하기 위해서는 사전 작업이 필요합니다.

◆ preload.js

public 폴더 아래 preload.js 파일을 만들어 아래 코드를 작성해줍니다.

const { ipcRenderer } = require("electron");

process.once("loaded", () => {
  window.ipcRenderer = ipcRenderer;
});

간단하게 작성하고 싶으면 아래 처럼 작성하시면 됩니다.

window.ipcRenderer = require("electron").ipcRenderer;

◆ electron.js 수정 1

electron.js에 코드를 추가 작성해줍니다. new BrowserWindow에 옵션을 추가해줍니다. mainWindow 객체를 생성하는 최종 코드는 아래와 같습니다.

mainWindow = new BrowserWindow({
  width: 800,
  height: 640,
  webPreferences: {
    nodeIntegration: true,
    contextIsolation: false,
    devTools: isDev,
    preload: path.join(__dirname, "preload.js")
  }
});

◆ App.js 수정

App.js의 코드는 아래와 같이 수정해줍니다. ipcRenderer를 사용하면 됩니다. 이벤트를 보낼 때는 send, 이벤트를 받을 때는 on을 사용하면 됩니다.

import { useEffect, useState } from "react";

const { ipcRenderer } = window;

const style = {
  margin: 10,
  padding: 10,
  border: "1px solid",
  borderRadius: 8
};

const App = () => {
  const [version, setVersion] = useState("");
  const [files, setFiles] = useState([]);

  useEffect(() => {
    ipcRenderer.send("app_version");

    ipcRenderer.on("app_version", (event, args) => {
      setVersion(args.version);
    });

    ipcRenderer.on("files", (event, args) => {
      setFiles(args.files);
    });
  }, []);

  return (
    <div>
      <div style={style}>
        <p>This is first electron desktop app.</p>
        <p>This application version is {version}</p>
      </div>
      <div style={style}>
        <button
          onClick={() => {
            ipcRenderer.send("files");
          }}
        >
          파일 명 가져오기
        </button>
        {files.map(file => (
          <p key={file}>{file}</p>
        ))}
      </div>
    </div>
  );
};

export default App;

코드는 간단하게 설명하면 아래와 같습니다. useEffect에서 app_version 이벤트를 보내고, app_version 이벤트를 받고, files 이벤트를 받습니다. 그리고 해당 이벤트가 발생한 경우 각각의 state에 값을 저장합니다. 그리고 파일 명 가져오기 버튼을 클릭하면 files 이벤트를 보냅니다.

◆ electron.js 수정 2

react에서 event를 보내면 electron에서 이벤트를 받아야겠죠? electron.js 파일에 코드를 추가해줍니다. electron.js에서는 ipcMain을 사용하면 됩니다. 이벤트를 받을 때는 on, 응답을 보낼 땐 event 객체를 사용하면 됩니다.

ipcMain.on("app_version", event => {
  event.reply("app_version", { version: app.getVersion() });
});

ipcMain.on("files", async event => {
  const result = await dialog
    .showOpenDialog(null, {
      filters: [
        {
          name: "Images",
          extensions: ["jpg", "png"]
        }
      ],
      properties: ["openFile", "multiSelections"]
    })
    .then(result => {
      const { canceled, filePaths } = result;

      if (canceled) return [];
      return filePaths;
    })
    .catch(err => {
      console.log(err);
      return [];
    });

  event.reply("files", { files: result });
});

코드를 간단하게 설명하자면 app_version 이벤트에서는 해당 app의 version 데이터를 전송해줍니다. 그리고 files 이벤트에서는 선택한 파일 명을 전송해줍니다.

실행 결과

위 프로그램의 실행 결과는 아래와 같습니다.

모든 데이터 통신이 정상적으로 이루어져 app version과 선택된 file name들이 잘 보여지고 있습니다.

이번 게시글에서는 react와 electron 사이 통신하는 방법을 알아보았습니다. ipcMain, ipcRenderer를 이용하면 쉽게 데이터를 주고 받을 수 있다는 것을 확인하였습니다. 다음 게시글에서는 설치 파일을 생성하는 방법을 알아보도록 하겠습니다.

참고자료

마지막

해당 내용은 틀릴 수도 있습니다. 틀린 내용이 있으면 조언 부탁드립니다.

반응형