Jayraj
Jayraj

Reputation: 430

Data from .CSV to JSON to Table (Table header is also dynamic) in React

In my code below onDataChange prop of Form element fetches data from .CSV to JSON via Papa.parse in Form Component and updates data in state of CommonComponent.

While loading data after choosing .CSV file Keys: Object.keys(this.props.data[0]) shows error that this.props.data[0] is null. However, {this.props.data.map(data=> <TableRows key={data.id} {...data}/>)} works fine and waits for data to be updated and rendered, even if both of them where null in the beginning.

Is there any way to handle this situation? I want to use Object.keys(this.props.data[0]) (i.e. The keys of Array's first object) to show table headers because for different .CSV table header will be different, and i want to render table for any size or scale .CSV.

Here's my code, I haven't shown Form component because, it's irrelevant.

const TableRows = (props) => {
    return (
        <tr>
            <td>{props.Account_Created}</td>
            <td>{props.City}</td>
            <td>{props.Country}</td>
            <td>{props.Last_Login}</td>
        </tr>
    );
};


class TableComponent extends Component {
    state = {
      Keys: []
    };

    componentDidMount() {
        this.setState({
            Keys: Object.keys(this.props.data[0])
        })
    }

    render() {
        return (
            <div>
                <table border="1">
                    <thead>
                        <tr>
                            {this.state.Keys.map(KEY => <th>{KEY}</th>)}
                        </tr>
                    </thead>
                    <tbody>
                        {this.props.data.map(data=> <TableRows key={data.id} {...data}/>)}
                    </tbody>
                </table>
            </div>
        );
    }
}


class CommonComponent extends Component {
    state = {
        data: []
    };

    updateData = (result) => {
        const data = result.data;
        this.setState({data});
    };

    render() {
        return (
            <div>
                <Form onDataChange={this.updateData}/>
                <TableComponent data={this.state.data}/>
            </div>
        );
    }
}

Upvotes: 0

Views: 1196

Answers (2)

Jayraj
Jayraj

Reputation: 430

I got the solution, Now i can show any JSON data coming to TableComponent via props. This is the solution for my problem, i came up after considering reply from chbchb55:

class TableRows extends Component {
    render() {
        return (
            <tr>
                {this.props.keys.map(Key=> <td>{this.props.data[Key]}</td>)}
            </tr>
        );
    }
}

class Table extends Component {
    render() {
        return (
            <table>
                <thead>
                    <tr>
                        {this.props.keys.map(Key => <th>{Key}</th>)}
                    </tr>
                </thead>
                <tbody>
                    {this.props.data.map(data=> <TableRows key={data.id} keys={this.props.keys} data={data}/>)}
                </tbody>
            </table>
        );
    }
}

class TableComponent extends Component {
    render() {
        return (
            <div>
                <Table keys={this.props.data.length > 0 ? Object.keys(this.props.data[0]) : []} data={this.props.data}/>
            </div>
        );
    }
}

Upvotes: 1

Andria
Andria

Reputation: 5075

Don't use componentDidMount

You're problem is that you're using componentDidMount to obtain the keys from the data object. When the component mounts there most likely won't be data yet.

Solution: Get the keys in render. This will work better for two reasons:

  1. You won't have to worry about waiting for the data to arrive, the component will update when it does.
  2. If you ever change the data, the headers will change as well.

Here is the code:

render() {
    return (
        <div>
            <table border="1">
                <thead>
                    <tr>
                        { this.props.data.length > 0 ? Object.keys(this.props.data[0]).map(KEY => <th>{KEY}</th>) : ''}
                    </tr>
                </thead>
                <tbody>
                    {this.props.data.map(data=> <TableRows key={data.id} {...data}/>)}
                </tbody>
            </table>
        </div>
    );
}

Upvotes: 1

Related Questions