Search code examples
reactjsreact-props

Eslint warning about super(props) removing it breaks code


I learn React and read code and now I see this Eslint warning

(props(

I refactor the code like this: removing props

constructor() {
    super();
    this.state = this.parse();
}

Now Eslint is happy but the code breaks because of probably props cant be used in the this.parse();

How is this suppose to work?

Completet code:

// Copyright (c) 2017 PlanGrid, Inc.

import React, { Component } from 'react';
import XLSX from 'xlsx';

import CsvViewer from './csv-viewer';
import WithFetching from '../file-viewer/fetch-wrapper';

class XlxsViewer extends Component {
    constructor(props) {
        super(props);
        this.state = this.parse();
    }

    parse() {
        const { data } = this.props;
        const dataArr = new Uint8Array(data);
        const arr = [];

        for (let i = 0; i !== dataArr.length; i += 1) {
            arr.push(String.fromCharCode(dataArr[i]));
        }

        const workbook = XLSX.read(arr.join(''), { type: 'binary' });
        const names = Object.keys(workbook.Sheets);
        const sheets = names.map(name => XLSX.utils.sheet_to_csv(workbook.Sheets[name]));

        return { sheets, names, curSheetIndex: 0 };
    }

    renderSheetNames(names) {
        const sheets = names.map((name, index) => (
            <input
                key={name}
                type="button"
                value={name}
                onClick={() => {
                    this.setState({ curSheetIndex: index });
                }}
            />
        ));

        return <div className="sheet-names">{sheets}</div>;
    }

    renderSheetData(sheet) {
        const csvProps = { ...this.props, data: sheet };
        return <CsvViewer {...csvProps} />;
    }

    render() {
        const { sheets, names, curSheetIndex } = this.state;
        return (
            <div className="spreadsheet-viewer">
                {this.renderSheetNames(names)}
                {this.renderSheetData(sheets[curSheetIndex || 0])}
            </div>
        );
    }
}

export default WithFetching(XlxsViewer);

Solution

  • An advice, move the parse() part to componentDidMount(). the constructor should be used in two cases only and shouldn't have any side-effects:

    • Initializing local state by assigning an object to this.state.
    • Binding event handler methods to an instance.

    Also, not calling super(props) will result in you not being able to have the actual values inside this.props as it will be undefined.

    A refactor to this code using this.setState() would look like:

    import React, { Component } from "react";
    import XLSX from "xlsx";
    
    import CsvViewer from "./csv-viewer";
    import WithFetching from "../file-viewer/fetch-wrapper";
    
    class XlxsViewer extends Component {
      componentDidMount() {
        this.parse();
      }
    
      parse() {
        const { data } = this.props;
        const dataArr = new Uint8Array(data);
        const arr = [];
    
        for (let i = 0; i !== dataArr.length; i += 1) {
          arr.push(String.fromCharCode(dataArr[i]));
        }
    
        const workbook = XLSX.read(arr.join(""), { type: "binary" });
        const names = Object.keys(workbook.Sheets);
        const sheets = names.map((name) =>
          XLSX.utils.sheet_to_csv(workbook.Sheets[name])
        );
    
        this.setState({ sheets, names, curSheetIndex: 0 });
      }
      ...
    }
    
    export default WithFetching(XlxsViewer);