Preview file CSV bằng reactjs

Giới thiệu

Tệp CSV là một tệp giá trị được phân cách bằng dấu phẩy. Khi văn bản và số được lưu trong một tệp CSV, thật dễ dàng để di chuyển chúng từ một chương trình khác. Ví dụ, bạn có thể xuất liên hệ của bạn từ Google ở định dạng CSV, và sau đó nhập chúng vào Outlook. Mỗi một trường trong tập tin CSV tương ứng với một bản ghi trong CSDL, hoặc một hàng trong bảng tính. Mỗi một trường trong bản ghi trong CSDL hoặc hàng trong bảng tính được ngăn cách bởi dấu phẩy. Tuy nhiên, bạn cũng có thể dùng các ký tự khác để ngăn cách các trường với nhau, như phím tab chẳng hạn.

Để mở file CSV ta có thể sử dụng các ứng dụng thông dụng như Libre Office trên ubuntu, hoặc đơn giản hơn là bất kì các text editor. Ở bài viết này mình sẽ demo 1 page preview file csv bằng reactjs.

Thực hiện

Khởi tạo project

Sử dụng rails khởi tạo project:

  1. Khởi tạo project sử dụng react: rails new PreviewCSV --webpack=react -d mysql
  2. Khởi động rails server: rails server
  3. Khởi động webpack: ./bin/webpack-dev-server

Cấu hình root page

  1. Tạo Homepage controller:

    # app/controllers/homepage_controller.rb
    class HomepageController < ApplicationController
      def index
      end
    end
    
  2. Cấu hình routes và tạo view homepage config/routes.rb

    # config/routes.rb
    Rails.application.routes.draw do
      root "homepage#index"
    end
    

    app/views/homepage/index.html.erb

    # app/views/homepage/index.html.erb
    <%= javascript_pack_tag 'application' %>
    

Implement preview CSV

  1. Tạo class PreviewCSV và get column headers:

     import React from 'react'
    
     export default class PreviewCSV extends React.Component {
       constructor(props) {
         super(props);
    
         this.state = { columns: null }
         this.csvFileToJSON = this.csvFileToJSON.bind(this);
         this.CSVToArray = this.CSVToArray.bind(this);
         this.preview = this.preview.bind(this);
       }
    
       preview() {
         const file = this.fileInput.files[0]
         this.setState({ file: file })
         this.csvFileToJSON(file).then(data => {
           const columns = Object.keys(data ? data[0] : [])
           this.setState({ columns: columns, datas: data })
         })
       }
    
       csvFileToJSON(file) {
         const self = this;
    
         return new Promise(function(resolve, reject) {
           var reader = new FileReader();
    
           reader.onerror = function(err) {
             reject(err);
           };
    
           reader.onload = function() {
             const data = self.CSVToArray(reader.result);
             resolve(data);
           };
           reader.readAsText(file);
         });
       }
    
       CSVToArray( strData, strDelimiter ){
           strDelimiter = (strDelimiter || ",");
           let objPattern = new RegExp(
             (
               "(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +
    
               "(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +
    
               "([^\"\\" + strDelimiter + "\\r\\n]*))"
             ),
             "gi");
    
           let arrData = [];
           let headers = [];
           let headersFound = false;
           let headerIndex = 0;
    
           let arrMatches = null;
    
           while(arrMatches = objPattern.exec( strData )) {
               let strMatchedDelimiter = arrMatches[ 1 ];
               if (strMatchedDelimiter.length && strMatchedDelimiter !== strDelimiter) {
                   arrData.push( {} );
                   headersFound = true;
                   headerIndex = 0;
               }
    
               let strMatchedValue;
               if (arrMatches[2]) {
                   strMatchedValue = arrMatches[2].replace(new RegExp( "\"\"", "g" ),"\"");
               } else {
                   strMatchedValue = arrMatches[3];
               }
    
               if (!headersFound) {
                 headers.push(strMatchedValue);
               } else {
                 arrData[arrData.length -1][headers[headerIndex]] = strMatchedValue;
                 headerIndex ++;
               }
           }
           return arrData;
       }
    
       render() {
         return(
           <div>
             <h1>Hi there</h1>
             <label>Choose a CSV file: </label>
             <input
               type="file"
               ref={(input) => { this.fileInput = input; }} />
             <br/>
             <input
               type="button"
               value="PREVIEW"
               onClick={this.preview}
             />
           </div>
         )
       }
     }
    
  2. Tạo table components hiển thị dữ liệu

    // app/javascript/packs/Table.js.jsx
    import React, { Component, PropTypes } from 'react';
    import TableHead from './TableHead';
    import TableBody from './TableBody';
    
    export function Table(props) {
      return (
        <div className="page-csvlist">
          <div className="table-content">
            <table>
              <TableHead columns={props.columns} />
              <TableBody displayData={props.displayData} columns={props.columns} />
            </table>
          </div>
        </div>
      );
    }
    
    export default Table;
    
  3. Gọi Table component vào PreviewCSV

    // app/javascript/packs/PreviewCSV.js.jsx
    ...
    <input
      type="button"
      value="PREVIEW"
      onClick={this.preview}
    />
    <Table displayData={datas ? datas : null} columns={columns ? columns : null} />
    ...
    

Kết quả

Chúc các bạn thành công ^^~ Github tutorial: https://github.com/nguyenthetoan/PreviewCSV ref tham khảo: https://stackoverflow.com/a/1293163