0

I have three components. A parent (MonthToDate) and two child (DisplayInvoice & DateSelector). Now, MonthToDate has HTML-select in it an there's an onChange associated with it which triggers groupBySelector function of same class. groupBySelector function's work is to set a state based on the select value. As soon as state is changed a new view is returned by GroupBy function.
Now, DateSelector component is also setting the state of parent component but the view is not rendered immediately. Instead it only get re-rendered whenever I use HTML-select of the parent component.
Now, I know that setState() is asynchronous but if the child component can get re-rendered for one type of value update using setState() why not for other event as well? (ie DateSelector is triggered).
This is parent component:

import React, { Component } from 'react';
import '../App.css';
import DisplayInvoice from './displayInvoice';
import DisplayCustomer from './displayCustomer';
import DisplayMonth from './displayMonth';
import DateSelector from './dateSelector';

var axios = require('axios');

class MonthToDate extends Component {

  constructor(props){
    super(props);
    this.state = {
      data:null,
      invoiceType:'invoice',
      urlInvoices:'',
      urlCustomer:'',
      isDateSet:false
    }
    //console.log(this.props.location.state.token);
     this.groupBySelector = this.groupBySelector.bind(this);
  }

  groupBySelector(event){
    if ((event.target.value)==="invoice"){
      this.setState({invoiceType:'invoice'})
    } else if ((event.target.value)==="customer") {
      this.setState({invoiceType:'customer'})
    } else if ((event.target.value)==="month") {
      this.setState({invoiceType:'month'})
    } else {
      this.setState({invoiceType:'invoice'})
    }
  }

  urlProducer = (date) => {
    this.setState({
      urlInvoices: ("http://localhost:3000/api/invoices"+date),
      urlCustomer: ("http://localhost:3000/api/invoices"+date+"&group-by=customerNumber"),
      isDateSet: true
    }, () => {console.log(this.state.urlCustomer);});
  }

  render() {
    return (
      //<DateSelector />
      <div>
      <DateSelector dateOnSelect={this.urlProducer}/>
      <select onChange={this.groupBySelector}>
        <option value="invoice">GROUP BY INVOICE</option>
        <option value="customer">GROUP BY CUSTOMER</option>
        <option value="month">GROUP BY MONTH</option>
      </select>
        <GroupBy token={this.props.location.state.token} invoiceType={this.state.invoiceType} isDateSet={this.state.isDateSet} urlInvoices={this.state.urlInvoices} urlCustomer={this.state.urlCustomer}/>
      </div>
    );
  }
}

export default MonthToDate;

function GroupBy(props) {
  if (props.invoiceType=='invoice') {
    return <DisplayInvoice token={props.token} url={(props.isDateSet) ? (props.urlInvoices) : "http://localhost:3000/api/monthtodate"}/>;
  } else if (props.invoiceType=='customer') {
    return <DisplayCustomer token={props.token} url={(props.isDateSet) ? (props.urlCustomer) : "http://localhost:3000/api/monthtodate?group-by=customerNumber"}/>;
  } else if (props.invoiceType=='month') {
    return <DisplayMonth token={props.token}/>;
  }
}

This is child component (ie DateSelector):

import React, { Component } from 'react';
import '../App.css';
import Moment from 'moment';

class DateSelector extends Component {

  constructor(props){
    super(props);
    this.state = {
      startDate:"",
      endDate:""
    }
  }

  dateHandler = (event) => {
    this.props.dateOnSelect("?startDate="+Moment(this.state.startDate).format('YYYY/MM/DD')
    +"&endDate="+Moment(this.state.endDate).format('YYYY/MM/DD'));
  }

  startDateOnChange = (event) => {
    this.setState({startDate: event.target.value});
  }

  endDateOnChange = (event) => {
    this.setState({endDate: event.target.value});
  }

  render() {
    return (
      <div>
        START DATE<input type="date" id="startDate" value={this.state.startDate} onChange={this.startDateOnChange}/>
        END DATE<input type="date" id="endDate" value={this.state.endDate} onChange={this.endDateOnChange}/>
        <button type="submit" onClick={this.dateHandler}>Submit</button>
      </div>
    );
  }
}

export default DateSelector;         

This is another child component ie DisplayInvoice (It should get updated both on groupBySelector() and on urlProducer = (date) =>{} as both are updating the state of parent component ) :

import React, { Component } from 'react';
import '../App.css';
import ListData from './listdata.js'
var axios = require('axios');

class DisplayInvoice extends Component {

  constructor(props){
    super(props);
    this.state = {
      data:[],
      url:"http://localhost:3000/api/monthtodate",
      baseUrl:"http://localhost:3000/api/monthtodate",
      billed:false,
      pending:false
    };
  }

  componentWillMount() {
    this.loadRevenue(this.state.url, this.props.token);
    console.log(this.props.url);        //trying to print the urlProducer's value here
  }

  setData(data){
      this.setState(data:data);
  }

  loadRevenue(url,token){
    axios({
      method:'get',
      url:url,
      headers: {
        Authorization: `Bearer ${token}`,
      },
    })
     .then( (response) => {
       this.setData(response.data);
     })
     .catch(function (error) {
       console.log("Error in loading Revenue "+error);
     });
  }

  togglePending = () => {
    this.setState((prevState) => ({pending: !prevState.pending}), () => {
      //  console.log("BILLED"+this.state.billed+" PENDING"+this.state.pending);
        this.filter(this.state.billed, this.state.pending);
      });
  }

  toggleBilled = () => {
    this.setState((prevState) => ({billed: !prevState.billed}), () => {
      //  console.log("BILLED"+this.state.billed+" PENDING"+this.state.pending);
        this.filter(this.state.billed, this.state.pending);
      });
  }

  filter = (billed,pending) => {
    if(billed==true && pending==true){
      this.setState((prevState) => ({url: prevState.baseUrl+"?invoicestatus=BILLED,PENDING"}), () => {this.loadRevenue(this.state.url, this.props.token)});
    } else if (billed==true && pending==false) {
      this.setState((prevState) => ({url: prevState.baseUrl+"?invoicestatus=BILLED"}), () => {this.loadRevenue(this.state.url, this.props.token)});
    } else if (billed==false && pending==true) {
      this.setState((prevState) => ({url: prevState.baseUrl+"?invoicestatus=PENDING"}), () => {this.loadRevenue(this.state.url, this.props.token)});
    }else if (billed==false && pending==false) {
      this.setState((prevState) => ({url: prevState.baseUrl}), () => {this.loadRevenue(this.state.url, this.props.token)});
    }
  }

  render() {
    let { pending, billed } = this.state;
    return (
      <div>
        <div>
          <input type="checkbox" name="invoicestatus" checked={billed} onChange={this.toggleBilled} value="BILLDED" />BILLDED<br />
          <input type="checkbox" name="invoicestatus" checked={pending} onChange={this.togglePending} value="PENDING" />PENDING<br />
        </div>
        <ListData data={this.state.data}/>
      </div>
    );
  }
};

export default DisplayInvoice;
  • What I'm missing?
  • I want to solve this in best way possible(standard approach) but without using redux .
noobie
  • 751
  • 4
  • 13
  • 33
  • I suggest you cut all the unnecessary code out and show the issue isolated, it will help you get an answer much faster - have a read of this https://stackoverflow.com/help/mcve – StudioTime Sep 15 '17 at 10:54
  • @DarrenSweeney done! – noobie Sep 15 '17 at 11:01
  • does the sytate of `DisplayInvoice` ever changed? or does it get new props? – Sagiv b.g Sep 15 '17 at 11:56
  • @Sag1v yes `DisplayInvoice` does get props from parent component. It's state also gets changed. I'm including whole code for your better understanding. – noobie Sep 15 '17 at 12:10
  • as i mentioned in [your other question](https://stackoverflow.com/a/46196599/3148807) (seems like it's the same code more or less) do not use side effects (ajax) in `componentWillMount`. this may be not directly related to your issue but it is a bad practice as mentioned in the [DOCS](https://facebook.github.io/react/docs/react-component.html#componentwillmount) – Sagiv b.g Sep 15 '17 at 12:14
  • @Sag1v replacing `componentWillMount` with `componentDidMount` doesn't solve the issue – noobie Sep 15 '17 at 12:51

0 Answers0