1

I have 100+ <td> to render. I'm fetching it using NodeJS backend, passing the data to the frontend, and using Redux to React components. I have many components that render fewer data and everything works great, but when it comes to this component, nothing happens until I refresh the page.

I tried using different life cycles (cpmponentWillMount, willRecieveProps, etc), but nothing seems to work.

I'm also using React-thunk and react-router

After the first refresh, there is no need for that anymore. So basically it only occurs when I first start the dev server.

I strongly believe that I have to use one of the component lifecycle functions and that I tried the wrong ones or in the wrong order?

ReportsData == > Where the rendering happens

class ReportsData extends Component {
constructor(props) {
    super(props);
    this.state = {
        allReports: []
}}

getReportsData = () => {
    return reportsApi.getReports().then(report => {
        this.setState(() => ({
            allReports: Object.assign([], report.data)
        })
    )});
}

componentWillMount() {
    this.getReportsData(this.props);
}

render() {

// const { reports } = this.props;

const { allReports } = this.state; 

let sortedReports = _.sortBy(reports, function(o) { return new moment(o.date) }).reverse();

const listReports = sortedReports.map(item => {
    return (

    <tr key={item.rowNumber}>
        <td> {item.year}</td>
        <td> {item.month}</td>
        <td> {item.bruto_ukupno}</td>
        <td> {item.neto_plata}</td>
        <td> {item.topli_obrok}</td>
        <td> {item.doprinosi}</td>
        <td> {parseInt(item.ukupno_plata, 10)}</td>

        <td className="table-actions">
            <Link to={{ pathname: '/reports/details', state: { item } }}>
                <PieChart size="21"/>
            </Link>
        </td>
    </tr>
)});

    return (

    <div className="portlet-body">
        <table className="table table-striped">
            <thead>
            <tr>
                <th>Year</th>
                <th>Month</th>
                <th>Gross</th>
                <th>Net</th>
                <th>Meals</th>
                <th>Taxes</th>
                <th>Salarys</th>
                <th>Details</th>
            </tr>
            </thead>
            <tbody>
                {listReports} 
            </tbody>
        </table>
    </div>
    );
}

}

ReportsAPI

    import axios from 'axios';
    import {baseApiUrl} from '../config/config';

    const reportsApiUrl = baseApiUrl + 'reports/'

    class ReportsApi {

        static getReports() {
            return axios({
                method: 'get',
                url: reportsApiUrl + 'getReports'
            })
        }
    }

export default ReportsApi;

reportsActions

    import * as actionTypes from '../actionTypes/actionTypes';
    import ReportsApi from "../api/reportsApi";

    export const getReports = (data) => {
        return {
            type: actionTypes.GET_REPORTS,
            data
        }
    }

export const getReportsAsync = () => {
    return dispatch => {
        return ReportsApi.getReports()
        .then(reports => {
            dispatch(getReports(reports.data));
        }).catch(error => {
            console.log('error while loading reports', error);
            throw(error);
        });
    };
}

This happens only the first time I start the DEV server So when I lift app my app every other component receives it's props, except this one, and I'm using the same logic everywhere.The only difference is in the amount of data being rendered. If I log out and log back in, everything is perfectly fine. If I refresh, go back and forward, it's all good, but as soon as i stop the server, start it again, only this component has that issue.

Dzenis H.
  • 4,658
  • 2
  • 17
  • 39
  • 2
    Could you show us some code so we can try to diagnose the issue? – Andrew Li Apr 17 '18 at 03:13
  • Sure, here it comes. Thanks! – Dzenis H. Apr 17 '18 at 03:15
  • 1
    @RayDonovan Try call the method `this.getReportsData(this.props);` in `componentDidMount` & use `componentWillRecieveProps` for receiving the props/data – Shiladitya Apr 17 '18 at 03:50
  • I'm receiving reports as props, but here I tried to do the achieve the same using the components state and backend API. In both cases, I have the same issue. I'm receiving reports as this.props.reports and it's there, but it doesn't render the first time I start the server. The allReports is something I tried to experiment with inside this component, without using Redux. I'm not trying to use both, but It's the same logic. – Dzenis H. Apr 17 '18 at 03:53
  • 1
    @RayDonovan So your passing some hardcoded prop `reports` for testing and it still renders only on refresh? – Andrew Li Apr 17 '18 at 03:54
  • Reports are coming from redux and they show up in the console.log, but after I refresh. allReports is something that I hardcoded using the same logic inside of the component. – Dzenis H. Apr 17 '18 at 03:57
  • 1
    @RayDonovan Any serverside debugging? – Andrew Li Apr 17 '18 at 03:59
  • For some reason, your setState call is being passed a function. when it really only needs an object, e.g. `this.setState({ allReports: Object.assign([], report.data) })` Maybe that was a hangover from the thunk version? – ChillyPenguin Apr 17 '18 at 04:47
  • @Li357 Yup, you were right. There was an unnecessary check if data coming from the API was undefined and Redux has to wait for the needed data. By the time that checks out, the component is already rendered without any data. I rearranged the code a little bit and now it's working. I hope my words make sense to you as much as they do to me :) Thanks for pointing me in the right direction. Cheers! – Dzenis H. Apr 17 '18 at 06:24

3 Answers3

1

Where are you importing and using this component. If could be that the data you are passing ReportData might not exist when you first render this component. throw a console.log(this.props) inside the componentDidMount() lifecycle method to see exactly what this.props is the first time your component gets rendered

AJ Genung
  • 329
  • 1
  • 8
  • export default ReportsData – Dzenis H. Apr 17 '18 at 03:43
  • @RayDonovan did you console.log it? what were the results the first time you start the app. before you refresh the page to get them to load. – AJ Genung Apr 17 '18 at 03:59
  • I cant comment on your question or the other Shiladitya's answer, but if your passing a prop down to this as a child component (which you quite possibly could be) then mapping State To Props is not needed, because this component is not actually getting anything from the Store, that is being controlled by this components parent. Let me know if you can get the results of that colsole.log. It would make sense that nothing is being rendered initially if this component is being rendered before the parent component even has the data to pass down to this component. – AJ Genung Apr 17 '18 at 04:20
0

try both didMount and willRecieveProps?

Seircn
  • 36
  • 3
0

There was an unnecessary check if data coming from the API was undefined and Redux has to wait for the needed data. By the time that checks out, the component is already rendered without any data. I rearranged the code a little bit and now it's working. Thanks for pointing me in the right direction.

So, the issue was on the backend in the reportsService module.

Here's the fix for future reference:

    const _ = require('lodash');

    module.exports = {
        mapReportsSheetToJson(data) {
          let result = [];
          for (let i = 2; i < data.length; i++) {
            let elem = {};
            data[1].map((item, index) => {
              // if (typeof data[i][index] !== 'undefined') {
                elem[item.toLocaleLowerCase()] = data[i][index];
              // }
            })
            elem['rowNumber'] = i + 1;
            result.push(elem);
          }
          return result;
        }
      }
Dzenis H.
  • 4,658
  • 2
  • 17
  • 39