본문 바로가기
개발/React

React Handsontable로 csv 편집기 만들기 (7)

by 피로물든딸기 2021. 6. 3.
반응형

프로젝트 전체 링크

 

이전 - (6) csv 파일 파싱하기

현재 - (7) App.js에서 파싱된 csv 파일 받기

다음 - (8) handsontable 설치하기

 

깃허브에서 코드 확인하기


이전 글에서 FileUpload에서 csv를 parsing하였다.

csv를 parsing한 내용은 App.js에서 보여주려고 한다.

parsing한 내용과 csv의 height와 width를 App.js에서 가지고 올 수 있도록 App.js를 아래와 같이 수정하자.

// App.js
import React, { useState } from "react";
//import * as lib from "./components/library";
import FileUpload from "./components/FileUpload";

const csvObjectDefault = {
  HEIGHT: 0,
  WIDTH: 0,
  csv: [],
};

const App = () => {
  const [csvObject, setCsvObject] = useState(csvObjectDefault);

  return (
    <div>
      <button onClick={() => console.log(csvObject)}>print csv</button>
      <div className="App">
        <FileUpload setCsvObject={setCsvObject} />
      </div>
    </div>
  );
};

export default App;

수정된 내용은 아래와 같다.

 

csvObject에 csv 파일의 정보(height, width, parsing된 내용)를 저장하도록 useState를 이용해 초기화한다.

const csvObjectDefault = {
  HEIGHT: 0,
  WIDTH: 0,
  csv: [],
};

const App = () => {
  const [csvObject, setCsvObject] = useState(csvObjectDefault);
  
  ...

 

csvObject가 제대로 들어왔는지 확인하기 위해 button을 추가한 후, onClicklog를 출력하도록 하자.

<button onClick={() => console.log(csvObject)}>print csv</button>

 

print csv 버튼을 클릭하면, 초기화 된 내용이 잘 출력된다.

 

FileUpload componentpropssetCsvObject를 넘긴다.

<FileUpload setCsvObject={setCsvObject} />

 

FileUpload.js에는 setCsvObject props를 받도록 수정하면 된다. (destructuring assignment, 비구조화 할당)

// FileUpload.js

...

const FileUpload = ({setCsvObject}) => { ... }

FileUpload에 setCsvObject를 넘겨 받았으므로, handleOnDrop과 handleUpload에도 넘겨주자.

// FileUpload.js

onDrop={(e) => lib.handleOnDrop(e, setDropFlag, setCsvObject)}
<input type="file" accept=".csv" onChange={(e) => lib.handleUpload(e, setCsvObject)}/>

 

마찬가지로, library에서도 handleOnDrop과 handleUpload에 setCsvObject를 넘겨주고 parsingCsv도 수정한다.

export const handleOnDrop = (e, setState, setCsvObject) => {
	...

    parsingCsv(fileReader.result, setCsvObject);
	
    ...
};

export const handleUpload = (e, setCsvObject) => {
	...
    
    parsingCsv(fileReader.result, setCsvObject);
	
	...
}

 

parsingCsv에서 setCsvObject를 넘겨받는다.

먼저 file을 parsing하기 전에 obj를 []로 초기화한다. 

그리고 sptLine을 순회하면서 height를 counting한다.

csvObject의 csv[]의 모든 length는 같으므로, 가장 첫 번째의 lengthwidth로 한다.

마지막으로 setCsvObject를 이용해 csvObject에 값을 저장한다.

export const parsingCsv = (file, setCsvObject) => {
  let height, width;
  let obj = {
    HEIGHT: 0,
    WIDTH: 0,
    csv: [],
  };

  obj.csv = [];

  let sptLine = file.split(/\r\n|\n/);
  console.log(sptLine);

  height = 0;
  for(let line of sptLine)
  {
    if(line === "") continue;

    let spt = mySplit(line, DELIMITER, APOSTROPHE);

    obj.csv.push(spt);
    height++;
  }

  width = obj.csv[0].length;

  obj.HEIGHT = height;
  obj.WIDTH = width;

  setCsvObject(obj);

  return;
}

 

코드를 수정한 후, file을 upload 한다.

그리고 print csv를 누르면 csv파일에 대한 정보가 App.js의 csvObject에 잘 들어간 것을 확인할 수 있다.

 

최종 코드는 아래와 같다.

// App.js
import React, { useState } from "react";
//import * as lib from "./components/library";
import FileUpload from "./components/FileUpload";

const csvObjectDefault = {
  HEIGHT: 0,
  WIDTH: 0,
  csv: [],
};

const App = () => {
  const [csvObject, setCsvObject] = useState(csvObjectDefault);

  return (
    <div>
      <button onClick={() => console.log(csvObject)}>print csv</button>
      <div className="App">
        <FileUpload setCsvObject={setCsvObject} />
      </div>
    </div>
  );
};

export default App;

 

// FileUpload.js
import React, { useState } from "react";
import * as lib from "./library.js";
import "../css/FileUpload.scss";

const FileUpload = ({setCsvObject}) => {
  const [dropFlag, setDropFlag] = useState(false);

  return (
    <div
      id="drag-drop-field"
      className={dropFlag ? "in" : ""}
      onDrop={(e) => lib.handleOnDrop(e, setDropFlag, setCsvObject)}
      onDragOver={(e) => lib.handleDragOver(e, setDropFlag)}
      onDragLeave={(e) => lib.handleOnDragLeave(e, setDropFlag)}
    >
      <p>drag & drop</p>
      <input type="file" accept=".csv" onChange={(e) => lib.handleUpload(e, setCsvObject)}/>
    </div>
  );
};

export default FileUpload;

 

// library.js

const DELIMITER = ',';
const APOSTROPHE = '"';

export const handleOnDragLeave = (e, setState) => {
  e.preventDefault();
  setState(false);
  return false;
};

export const handleDragOver = (e, setState) => {
  e.preventDefault();
  setState(true);
  return false;
};

export const handleOnDrop = (e, setState, setCsvObject) => {
  e.preventDefault();

  let file = e.dataTransfer.files[0];
  let fileReader = new FileReader();

  fileReader.readAsText(file, "utf-8"); // or euc-kr

  fileReader.onload = function () {
    //console.log(fileReader.result); 
    parsingCsv(fileReader.result, setCsvObject);
    return;
  };

  setState(false);
  return false; 
};

export const handleUpload = (e, setCsvObject) => {
  let file = e.target.files[0];
  let fileReader = new FileReader();
  
  if(file === undefined) return; /* 방어 코드 추가 */

  fileReader.readAsText(file, "utf-8"); // or euc-kr

  fileReader.onload = function () {
    //console.log(fileReader.result); 
    parsingCsv(fileReader.result, setCsvObject);
  };
}

export const mySplit = (line, delimiter, ignore) => {
  let spt = [];
  let tmp = "";
  let flag = false;

  for(let i = 0; i < line.length; i++)
  {
    if(ignore === line[i] && flag === true) 
    {
      flag = false;
      continue;
    }
    else if(ignore === line[i])
    {
      flag = true;
      continue;
    } 
    
    if(line[i] === delimiter && flag === false) {
      spt.push(tmp);
      tmp = "";

      continue;
    }

    tmp += line[i];
  }

  spt.push(tmp);

  return spt;
}

export const parsingCsv = (file, setCsvObject) => {
  let height, width;
  let obj = {
    HEIGHT: 0,
    WIDTH: 0,
    csv: [],
  };

  obj.csv = [];

  let sptLine = file.split(/\r\n|\n/);
  console.log(sptLine);

  height = 0;
  for(let line of sptLine)
  {
    if(line === "") continue;

    let spt = mySplit(line, DELIMITER, APOSTROPHE);

    obj.csv.push(spt);
    height++;
  }

  width = obj.csv[0].length;

  obj.HEIGHT = height;
  obj.WIDTH = width;

  setCsvObject(obj);

  return;
}

이전 - (6) csv 파일 파싱하기

다음 - (8) handsontable 설치하기

반응형

댓글