child component does not re-render when props change











up vote
0
down vote

favorite












Problem:



The first page of my app shows list of Sale Invoices.



I select one which runs a function taking id of the clicked invoice as argument and gets its details via API call.



Customer component rendered from SaleInvoice has a input box (Typeahead component) which is supposed to show customerName passed down from SaleInvoice but does not do so correctly. It is sometimes blank and when I go back to the first page (list of Sale Invoices) and select other Sale Invoice, the customerName of the previous Sale Invoice. I checked the console log (see the line after <React.Fragment> in Customer component) and I can see the correct values of customerName in the state shown by reducers.



Initially, SaleInvoice was a stateful component but had no state object. I made it stateful to fetch my data via API in componentWillMount. Due to the above problem, I tried this:



added customerName in state in SaleInvoice



changed this.props.customerName to this.state.customerName in Customer props



used




getDerivedStateFromProps()




which says I cannot use componentWillMount



Also, tried shouldComponentUpdate and some other stuff.
Nothing works. Kindly help. If more code needs to be posted, please let me know.



relevant slice of reducer



case actionTypes.INVOICE_BY_ID_SUCCESS:
let customerData = action.payload[0];
let saleInvoiceData = action.payload[1];
let newState = Object.assign({}, state);
newState.loading = false;
newState.error = null;
newState.customerInfo = {
...state.customerInfo,
id: customerData.id,
place: customerData.place,
addressLineOne: customerData.address_line_one,
};
newState.saleInvoiceId = saleInvoiceData.id;
newState.customerName = saleInvoiceData.customer_name;
newState.serialNumber = saleInvoiceData.serial_number;
newState.amountBeforeFreight = saleInvoiceData.amount_before_freight;
newState.freight = saleInvoiceData.freight;
newState.amountAfterFreight = saleInvoiceData.amount_after_freight;
return newState;


SaleInvoiceContainer.js (excluding imports)



const mapStateToProps = (state, ownProps) => {
console.log(`ownProps ${ownProps}`);
console.log(ownProps);
return {
customerLoading: state.saleInvoiceReducer.customerLoading,
customerError: state.saleInvoiceReducer.customerError,

productError: state.lineItemsReducer.error,
productLoading: state.lineItemsReducer.loading,

saleInvoiceError: state.saleInvoiceReducer.error,
saleInvoiceLoading: state.lineItemsReducer.error,

saleInvoiceId: state.saleInvoiceReducer.saleInvoiceId,
customerData: state.saleInvoiceReducer.customerData, // data of all customers
productData: state.lineItemsReducer.productData, // data of all products
customerInfo: state.saleInvoiceReducer.customerInfo, // data of current customer
addingCustomer: state.saleInvoiceReducer.addingCustomer, // modal show/hide
customerName: state.saleInvoiceReducer.customerName, // input field name
grandTotal: subTotalSelector(state),
};
};
const mapDispatchToProps = (dispatch, ownProps) => {
return {
fetchCustomer: () => dispatch(fetchCustomer()),
fetchProduct: () => dispatch(fetchProduct()),
getInvoiceById: () =>
dispatch(getInvoiceById(ownProps.location.state.id)),
onBlurCustomerName: event => dispatch(onBlurCustomerName(event)),
stopAddingCustomer: () => dispatch(stopAddingCustomer()),
};
};




const SaleInvoiceContainer = connect(
mapStateToProps,
mapDispatchToProps,
)(SaleInvoice);


SaleInvoice.js (excluding imports)



class SaleInvoice extends React.Component {
state = {
customerName: '',
};

componentWillMount() {
// if api is called from here, state will not update when api updates
// props change cause re-render
this.props.getInvoiceById();
this.props.fetchCustomer();
this.props.fetchProduct();
}
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.customeName !== prevState.customerName) {
return {customerName: nextProps.customerName};
} else return null;
}
componentDidUpdate(prevProps, prevState) {
if (prevProps.customerName !== this.state.customerName) {
let customerName = this.state.customerName;
//Perform some operation here
this.setState({customerName});
}
}



render() {
console.log(this.props);
let ui = this.props.customerError ? (
<p>Customers failed to load!</p>
) : (
<Spinner />
);

let printLink = '/sale-invoice/' + this.props.saleInvoiceId + '/print';
let sui = this.props.productError ? (
<p>Products failed to load!</p>
) : (
<Spinner />
);
if (
!this.props.customerLoading &&
!this.props.customerError &&
!this.props.error
) {
console.log('Customers have been loaded');
ui = (
<React.Fragment>
<Modal
show={this.props.addingCustomer}
modalClosed={this.props.stopAddingCustomer}
customerData={this.props.customerData}
name={this.state.customerName}
/>
<div className={classes.mainContainerTitle}>
{console.log(this.props.grandTotal)}
<h5 className={classes.pageTitle}>Sale Invoice</h5>
<NavLink className={classes.NavLink} to={printLink}>
Print
</NavLink>
{/*<button>Print</button>*/}
</div>
<rs.Container
fluid
className={[classes.mainContainer, classes.containerFluid].join(
'',
)}>
<rs.Row className={classes.firstRow}>
<Customer
customerData={this.props.customerData}
onBlurCustomerName={this.props.onBlurCustomerName}
customerInfo={this.props.customerInfo}
customerName={this.state.customerName}
/>
<SaleInvoiceSummary grandTotal={this.props.grandTotal} />
</rs.Row>
</rs.Container>
</React.Fragment>
);
}
if (
!this.props.productLoading &&
!this.props.productError &&
!this.props.error
) {
console.log('Products have been loaded');
sui = (
<React.Fragment>
<rs.Container fluid className={classes.gridContainer}>
<LineItemsContainer />
</rs.Container>
</React.Fragment>
);
}
return (
<React.Fragment>
{ui}
{sui}
</React.Fragment>


);
}

}


Customer.js (exluding imports)



const Customer = props => {
function _renderMenuItemChildren(option, props, index) {
return [
<Highlighter key="name" search={props.text}>
{option.name}
</Highlighter>,
<div key="place">
<small>Place: {option.place}</small>
</div>,
];
}
return (
<React.Fragment>
{console.log(props.customerName)}
<rs.Card col="sm-4" className={classes.firstCard}>
<rs.CardHeader className={classes.cardHeader}>
Customer Details
</rs.CardHeader>
<rs.CardBody className={classes.cardBodySaleInvoice}>
<rs.Label>Name</rs.Label>
<React.Fragment>
<Typeahead
className={classes.customerTypeahead}
defaultInputValue={props.customerName}
allowNew={true}
newSelectionPrefix="Add New: "
disabled={false}
labelKey="name" // this determines what array key value to show
multiple={false}
options={props.customerData}
placeholder="Choose a customer..."
onBlur={event => props.onBlurCustomerName(event)}
renderMenuItemChildren={_renderMenuItemChildren}
/>
<rs.FormGroup />
</React.Fragment>
<div className={classes.customerCardBody}>
<rs.Label>Address</rs.Label>
<div className={classes.address}>
{props.customerInfo.addressLineOne}
<br />
{props.customerInfo.addressLineTwo}
<br />
{props.customerInfo.address_line_three}
<br />
{props.customerInfo.contact_no_one}
<br />
{props.customerInfo.gst_number}
<br />
<button>Edit</button>
</div>
</div>
</rs.CardBody>
</rs.Card>
</React.Fragment>
);
};


(PS: I am new to React, additional comments/criticism regarding the code will be helpful)










share|improve this question




























    up vote
    0
    down vote

    favorite












    Problem:



    The first page of my app shows list of Sale Invoices.



    I select one which runs a function taking id of the clicked invoice as argument and gets its details via API call.



    Customer component rendered from SaleInvoice has a input box (Typeahead component) which is supposed to show customerName passed down from SaleInvoice but does not do so correctly. It is sometimes blank and when I go back to the first page (list of Sale Invoices) and select other Sale Invoice, the customerName of the previous Sale Invoice. I checked the console log (see the line after <React.Fragment> in Customer component) and I can see the correct values of customerName in the state shown by reducers.



    Initially, SaleInvoice was a stateful component but had no state object. I made it stateful to fetch my data via API in componentWillMount. Due to the above problem, I tried this:



    added customerName in state in SaleInvoice



    changed this.props.customerName to this.state.customerName in Customer props



    used




    getDerivedStateFromProps()




    which says I cannot use componentWillMount



    Also, tried shouldComponentUpdate and some other stuff.
    Nothing works. Kindly help. If more code needs to be posted, please let me know.



    relevant slice of reducer



    case actionTypes.INVOICE_BY_ID_SUCCESS:
    let customerData = action.payload[0];
    let saleInvoiceData = action.payload[1];
    let newState = Object.assign({}, state);
    newState.loading = false;
    newState.error = null;
    newState.customerInfo = {
    ...state.customerInfo,
    id: customerData.id,
    place: customerData.place,
    addressLineOne: customerData.address_line_one,
    };
    newState.saleInvoiceId = saleInvoiceData.id;
    newState.customerName = saleInvoiceData.customer_name;
    newState.serialNumber = saleInvoiceData.serial_number;
    newState.amountBeforeFreight = saleInvoiceData.amount_before_freight;
    newState.freight = saleInvoiceData.freight;
    newState.amountAfterFreight = saleInvoiceData.amount_after_freight;
    return newState;


    SaleInvoiceContainer.js (excluding imports)



    const mapStateToProps = (state, ownProps) => {
    console.log(`ownProps ${ownProps}`);
    console.log(ownProps);
    return {
    customerLoading: state.saleInvoiceReducer.customerLoading,
    customerError: state.saleInvoiceReducer.customerError,

    productError: state.lineItemsReducer.error,
    productLoading: state.lineItemsReducer.loading,

    saleInvoiceError: state.saleInvoiceReducer.error,
    saleInvoiceLoading: state.lineItemsReducer.error,

    saleInvoiceId: state.saleInvoiceReducer.saleInvoiceId,
    customerData: state.saleInvoiceReducer.customerData, // data of all customers
    productData: state.lineItemsReducer.productData, // data of all products
    customerInfo: state.saleInvoiceReducer.customerInfo, // data of current customer
    addingCustomer: state.saleInvoiceReducer.addingCustomer, // modal show/hide
    customerName: state.saleInvoiceReducer.customerName, // input field name
    grandTotal: subTotalSelector(state),
    };
    };
    const mapDispatchToProps = (dispatch, ownProps) => {
    return {
    fetchCustomer: () => dispatch(fetchCustomer()),
    fetchProduct: () => dispatch(fetchProduct()),
    getInvoiceById: () =>
    dispatch(getInvoiceById(ownProps.location.state.id)),
    onBlurCustomerName: event => dispatch(onBlurCustomerName(event)),
    stopAddingCustomer: () => dispatch(stopAddingCustomer()),
    };
    };




    const SaleInvoiceContainer = connect(
    mapStateToProps,
    mapDispatchToProps,
    )(SaleInvoice);


    SaleInvoice.js (excluding imports)



    class SaleInvoice extends React.Component {
    state = {
    customerName: '',
    };

    componentWillMount() {
    // if api is called from here, state will not update when api updates
    // props change cause re-render
    this.props.getInvoiceById();
    this.props.fetchCustomer();
    this.props.fetchProduct();
    }
    static getDerivedStateFromProps(nextProps, prevState) {
    if (nextProps.customeName !== prevState.customerName) {
    return {customerName: nextProps.customerName};
    } else return null;
    }
    componentDidUpdate(prevProps, prevState) {
    if (prevProps.customerName !== this.state.customerName) {
    let customerName = this.state.customerName;
    //Perform some operation here
    this.setState({customerName});
    }
    }



    render() {
    console.log(this.props);
    let ui = this.props.customerError ? (
    <p>Customers failed to load!</p>
    ) : (
    <Spinner />
    );

    let printLink = '/sale-invoice/' + this.props.saleInvoiceId + '/print';
    let sui = this.props.productError ? (
    <p>Products failed to load!</p>
    ) : (
    <Spinner />
    );
    if (
    !this.props.customerLoading &&
    !this.props.customerError &&
    !this.props.error
    ) {
    console.log('Customers have been loaded');
    ui = (
    <React.Fragment>
    <Modal
    show={this.props.addingCustomer}
    modalClosed={this.props.stopAddingCustomer}
    customerData={this.props.customerData}
    name={this.state.customerName}
    />
    <div className={classes.mainContainerTitle}>
    {console.log(this.props.grandTotal)}
    <h5 className={classes.pageTitle}>Sale Invoice</h5>
    <NavLink className={classes.NavLink} to={printLink}>
    Print
    </NavLink>
    {/*<button>Print</button>*/}
    </div>
    <rs.Container
    fluid
    className={[classes.mainContainer, classes.containerFluid].join(
    '',
    )}>
    <rs.Row className={classes.firstRow}>
    <Customer
    customerData={this.props.customerData}
    onBlurCustomerName={this.props.onBlurCustomerName}
    customerInfo={this.props.customerInfo}
    customerName={this.state.customerName}
    />
    <SaleInvoiceSummary grandTotal={this.props.grandTotal} />
    </rs.Row>
    </rs.Container>
    </React.Fragment>
    );
    }
    if (
    !this.props.productLoading &&
    !this.props.productError &&
    !this.props.error
    ) {
    console.log('Products have been loaded');
    sui = (
    <React.Fragment>
    <rs.Container fluid className={classes.gridContainer}>
    <LineItemsContainer />
    </rs.Container>
    </React.Fragment>
    );
    }
    return (
    <React.Fragment>
    {ui}
    {sui}
    </React.Fragment>


    );
    }

    }


    Customer.js (exluding imports)



    const Customer = props => {
    function _renderMenuItemChildren(option, props, index) {
    return [
    <Highlighter key="name" search={props.text}>
    {option.name}
    </Highlighter>,
    <div key="place">
    <small>Place: {option.place}</small>
    </div>,
    ];
    }
    return (
    <React.Fragment>
    {console.log(props.customerName)}
    <rs.Card col="sm-4" className={classes.firstCard}>
    <rs.CardHeader className={classes.cardHeader}>
    Customer Details
    </rs.CardHeader>
    <rs.CardBody className={classes.cardBodySaleInvoice}>
    <rs.Label>Name</rs.Label>
    <React.Fragment>
    <Typeahead
    className={classes.customerTypeahead}
    defaultInputValue={props.customerName}
    allowNew={true}
    newSelectionPrefix="Add New: "
    disabled={false}
    labelKey="name" // this determines what array key value to show
    multiple={false}
    options={props.customerData}
    placeholder="Choose a customer..."
    onBlur={event => props.onBlurCustomerName(event)}
    renderMenuItemChildren={_renderMenuItemChildren}
    />
    <rs.FormGroup />
    </React.Fragment>
    <div className={classes.customerCardBody}>
    <rs.Label>Address</rs.Label>
    <div className={classes.address}>
    {props.customerInfo.addressLineOne}
    <br />
    {props.customerInfo.addressLineTwo}
    <br />
    {props.customerInfo.address_line_three}
    <br />
    {props.customerInfo.contact_no_one}
    <br />
    {props.customerInfo.gst_number}
    <br />
    <button>Edit</button>
    </div>
    </div>
    </rs.CardBody>
    </rs.Card>
    </React.Fragment>
    );
    };


    (PS: I am new to React, additional comments/criticism regarding the code will be helpful)










    share|improve this question


























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      Problem:



      The first page of my app shows list of Sale Invoices.



      I select one which runs a function taking id of the clicked invoice as argument and gets its details via API call.



      Customer component rendered from SaleInvoice has a input box (Typeahead component) which is supposed to show customerName passed down from SaleInvoice but does not do so correctly. It is sometimes blank and when I go back to the first page (list of Sale Invoices) and select other Sale Invoice, the customerName of the previous Sale Invoice. I checked the console log (see the line after <React.Fragment> in Customer component) and I can see the correct values of customerName in the state shown by reducers.



      Initially, SaleInvoice was a stateful component but had no state object. I made it stateful to fetch my data via API in componentWillMount. Due to the above problem, I tried this:



      added customerName in state in SaleInvoice



      changed this.props.customerName to this.state.customerName in Customer props



      used




      getDerivedStateFromProps()




      which says I cannot use componentWillMount



      Also, tried shouldComponentUpdate and some other stuff.
      Nothing works. Kindly help. If more code needs to be posted, please let me know.



      relevant slice of reducer



      case actionTypes.INVOICE_BY_ID_SUCCESS:
      let customerData = action.payload[0];
      let saleInvoiceData = action.payload[1];
      let newState = Object.assign({}, state);
      newState.loading = false;
      newState.error = null;
      newState.customerInfo = {
      ...state.customerInfo,
      id: customerData.id,
      place: customerData.place,
      addressLineOne: customerData.address_line_one,
      };
      newState.saleInvoiceId = saleInvoiceData.id;
      newState.customerName = saleInvoiceData.customer_name;
      newState.serialNumber = saleInvoiceData.serial_number;
      newState.amountBeforeFreight = saleInvoiceData.amount_before_freight;
      newState.freight = saleInvoiceData.freight;
      newState.amountAfterFreight = saleInvoiceData.amount_after_freight;
      return newState;


      SaleInvoiceContainer.js (excluding imports)



      const mapStateToProps = (state, ownProps) => {
      console.log(`ownProps ${ownProps}`);
      console.log(ownProps);
      return {
      customerLoading: state.saleInvoiceReducer.customerLoading,
      customerError: state.saleInvoiceReducer.customerError,

      productError: state.lineItemsReducer.error,
      productLoading: state.lineItemsReducer.loading,

      saleInvoiceError: state.saleInvoiceReducer.error,
      saleInvoiceLoading: state.lineItemsReducer.error,

      saleInvoiceId: state.saleInvoiceReducer.saleInvoiceId,
      customerData: state.saleInvoiceReducer.customerData, // data of all customers
      productData: state.lineItemsReducer.productData, // data of all products
      customerInfo: state.saleInvoiceReducer.customerInfo, // data of current customer
      addingCustomer: state.saleInvoiceReducer.addingCustomer, // modal show/hide
      customerName: state.saleInvoiceReducer.customerName, // input field name
      grandTotal: subTotalSelector(state),
      };
      };
      const mapDispatchToProps = (dispatch, ownProps) => {
      return {
      fetchCustomer: () => dispatch(fetchCustomer()),
      fetchProduct: () => dispatch(fetchProduct()),
      getInvoiceById: () =>
      dispatch(getInvoiceById(ownProps.location.state.id)),
      onBlurCustomerName: event => dispatch(onBlurCustomerName(event)),
      stopAddingCustomer: () => dispatch(stopAddingCustomer()),
      };
      };




      const SaleInvoiceContainer = connect(
      mapStateToProps,
      mapDispatchToProps,
      )(SaleInvoice);


      SaleInvoice.js (excluding imports)



      class SaleInvoice extends React.Component {
      state = {
      customerName: '',
      };

      componentWillMount() {
      // if api is called from here, state will not update when api updates
      // props change cause re-render
      this.props.getInvoiceById();
      this.props.fetchCustomer();
      this.props.fetchProduct();
      }
      static getDerivedStateFromProps(nextProps, prevState) {
      if (nextProps.customeName !== prevState.customerName) {
      return {customerName: nextProps.customerName};
      } else return null;
      }
      componentDidUpdate(prevProps, prevState) {
      if (prevProps.customerName !== this.state.customerName) {
      let customerName = this.state.customerName;
      //Perform some operation here
      this.setState({customerName});
      }
      }



      render() {
      console.log(this.props);
      let ui = this.props.customerError ? (
      <p>Customers failed to load!</p>
      ) : (
      <Spinner />
      );

      let printLink = '/sale-invoice/' + this.props.saleInvoiceId + '/print';
      let sui = this.props.productError ? (
      <p>Products failed to load!</p>
      ) : (
      <Spinner />
      );
      if (
      !this.props.customerLoading &&
      !this.props.customerError &&
      !this.props.error
      ) {
      console.log('Customers have been loaded');
      ui = (
      <React.Fragment>
      <Modal
      show={this.props.addingCustomer}
      modalClosed={this.props.stopAddingCustomer}
      customerData={this.props.customerData}
      name={this.state.customerName}
      />
      <div className={classes.mainContainerTitle}>
      {console.log(this.props.grandTotal)}
      <h5 className={classes.pageTitle}>Sale Invoice</h5>
      <NavLink className={classes.NavLink} to={printLink}>
      Print
      </NavLink>
      {/*<button>Print</button>*/}
      </div>
      <rs.Container
      fluid
      className={[classes.mainContainer, classes.containerFluid].join(
      '',
      )}>
      <rs.Row className={classes.firstRow}>
      <Customer
      customerData={this.props.customerData}
      onBlurCustomerName={this.props.onBlurCustomerName}
      customerInfo={this.props.customerInfo}
      customerName={this.state.customerName}
      />
      <SaleInvoiceSummary grandTotal={this.props.grandTotal} />
      </rs.Row>
      </rs.Container>
      </React.Fragment>
      );
      }
      if (
      !this.props.productLoading &&
      !this.props.productError &&
      !this.props.error
      ) {
      console.log('Products have been loaded');
      sui = (
      <React.Fragment>
      <rs.Container fluid className={classes.gridContainer}>
      <LineItemsContainer />
      </rs.Container>
      </React.Fragment>
      );
      }
      return (
      <React.Fragment>
      {ui}
      {sui}
      </React.Fragment>


      );
      }

      }


      Customer.js (exluding imports)



      const Customer = props => {
      function _renderMenuItemChildren(option, props, index) {
      return [
      <Highlighter key="name" search={props.text}>
      {option.name}
      </Highlighter>,
      <div key="place">
      <small>Place: {option.place}</small>
      </div>,
      ];
      }
      return (
      <React.Fragment>
      {console.log(props.customerName)}
      <rs.Card col="sm-4" className={classes.firstCard}>
      <rs.CardHeader className={classes.cardHeader}>
      Customer Details
      </rs.CardHeader>
      <rs.CardBody className={classes.cardBodySaleInvoice}>
      <rs.Label>Name</rs.Label>
      <React.Fragment>
      <Typeahead
      className={classes.customerTypeahead}
      defaultInputValue={props.customerName}
      allowNew={true}
      newSelectionPrefix="Add New: "
      disabled={false}
      labelKey="name" // this determines what array key value to show
      multiple={false}
      options={props.customerData}
      placeholder="Choose a customer..."
      onBlur={event => props.onBlurCustomerName(event)}
      renderMenuItemChildren={_renderMenuItemChildren}
      />
      <rs.FormGroup />
      </React.Fragment>
      <div className={classes.customerCardBody}>
      <rs.Label>Address</rs.Label>
      <div className={classes.address}>
      {props.customerInfo.addressLineOne}
      <br />
      {props.customerInfo.addressLineTwo}
      <br />
      {props.customerInfo.address_line_three}
      <br />
      {props.customerInfo.contact_no_one}
      <br />
      {props.customerInfo.gst_number}
      <br />
      <button>Edit</button>
      </div>
      </div>
      </rs.CardBody>
      </rs.Card>
      </React.Fragment>
      );
      };


      (PS: I am new to React, additional comments/criticism regarding the code will be helpful)










      share|improve this question















      Problem:



      The first page of my app shows list of Sale Invoices.



      I select one which runs a function taking id of the clicked invoice as argument and gets its details via API call.



      Customer component rendered from SaleInvoice has a input box (Typeahead component) which is supposed to show customerName passed down from SaleInvoice but does not do so correctly. It is sometimes blank and when I go back to the first page (list of Sale Invoices) and select other Sale Invoice, the customerName of the previous Sale Invoice. I checked the console log (see the line after <React.Fragment> in Customer component) and I can see the correct values of customerName in the state shown by reducers.



      Initially, SaleInvoice was a stateful component but had no state object. I made it stateful to fetch my data via API in componentWillMount. Due to the above problem, I tried this:



      added customerName in state in SaleInvoice



      changed this.props.customerName to this.state.customerName in Customer props



      used




      getDerivedStateFromProps()




      which says I cannot use componentWillMount



      Also, tried shouldComponentUpdate and some other stuff.
      Nothing works. Kindly help. If more code needs to be posted, please let me know.



      relevant slice of reducer



      case actionTypes.INVOICE_BY_ID_SUCCESS:
      let customerData = action.payload[0];
      let saleInvoiceData = action.payload[1];
      let newState = Object.assign({}, state);
      newState.loading = false;
      newState.error = null;
      newState.customerInfo = {
      ...state.customerInfo,
      id: customerData.id,
      place: customerData.place,
      addressLineOne: customerData.address_line_one,
      };
      newState.saleInvoiceId = saleInvoiceData.id;
      newState.customerName = saleInvoiceData.customer_name;
      newState.serialNumber = saleInvoiceData.serial_number;
      newState.amountBeforeFreight = saleInvoiceData.amount_before_freight;
      newState.freight = saleInvoiceData.freight;
      newState.amountAfterFreight = saleInvoiceData.amount_after_freight;
      return newState;


      SaleInvoiceContainer.js (excluding imports)



      const mapStateToProps = (state, ownProps) => {
      console.log(`ownProps ${ownProps}`);
      console.log(ownProps);
      return {
      customerLoading: state.saleInvoiceReducer.customerLoading,
      customerError: state.saleInvoiceReducer.customerError,

      productError: state.lineItemsReducer.error,
      productLoading: state.lineItemsReducer.loading,

      saleInvoiceError: state.saleInvoiceReducer.error,
      saleInvoiceLoading: state.lineItemsReducer.error,

      saleInvoiceId: state.saleInvoiceReducer.saleInvoiceId,
      customerData: state.saleInvoiceReducer.customerData, // data of all customers
      productData: state.lineItemsReducer.productData, // data of all products
      customerInfo: state.saleInvoiceReducer.customerInfo, // data of current customer
      addingCustomer: state.saleInvoiceReducer.addingCustomer, // modal show/hide
      customerName: state.saleInvoiceReducer.customerName, // input field name
      grandTotal: subTotalSelector(state),
      };
      };
      const mapDispatchToProps = (dispatch, ownProps) => {
      return {
      fetchCustomer: () => dispatch(fetchCustomer()),
      fetchProduct: () => dispatch(fetchProduct()),
      getInvoiceById: () =>
      dispatch(getInvoiceById(ownProps.location.state.id)),
      onBlurCustomerName: event => dispatch(onBlurCustomerName(event)),
      stopAddingCustomer: () => dispatch(stopAddingCustomer()),
      };
      };




      const SaleInvoiceContainer = connect(
      mapStateToProps,
      mapDispatchToProps,
      )(SaleInvoice);


      SaleInvoice.js (excluding imports)



      class SaleInvoice extends React.Component {
      state = {
      customerName: '',
      };

      componentWillMount() {
      // if api is called from here, state will not update when api updates
      // props change cause re-render
      this.props.getInvoiceById();
      this.props.fetchCustomer();
      this.props.fetchProduct();
      }
      static getDerivedStateFromProps(nextProps, prevState) {
      if (nextProps.customeName !== prevState.customerName) {
      return {customerName: nextProps.customerName};
      } else return null;
      }
      componentDidUpdate(prevProps, prevState) {
      if (prevProps.customerName !== this.state.customerName) {
      let customerName = this.state.customerName;
      //Perform some operation here
      this.setState({customerName});
      }
      }



      render() {
      console.log(this.props);
      let ui = this.props.customerError ? (
      <p>Customers failed to load!</p>
      ) : (
      <Spinner />
      );

      let printLink = '/sale-invoice/' + this.props.saleInvoiceId + '/print';
      let sui = this.props.productError ? (
      <p>Products failed to load!</p>
      ) : (
      <Spinner />
      );
      if (
      !this.props.customerLoading &&
      !this.props.customerError &&
      !this.props.error
      ) {
      console.log('Customers have been loaded');
      ui = (
      <React.Fragment>
      <Modal
      show={this.props.addingCustomer}
      modalClosed={this.props.stopAddingCustomer}
      customerData={this.props.customerData}
      name={this.state.customerName}
      />
      <div className={classes.mainContainerTitle}>
      {console.log(this.props.grandTotal)}
      <h5 className={classes.pageTitle}>Sale Invoice</h5>
      <NavLink className={classes.NavLink} to={printLink}>
      Print
      </NavLink>
      {/*<button>Print</button>*/}
      </div>
      <rs.Container
      fluid
      className={[classes.mainContainer, classes.containerFluid].join(
      '',
      )}>
      <rs.Row className={classes.firstRow}>
      <Customer
      customerData={this.props.customerData}
      onBlurCustomerName={this.props.onBlurCustomerName}
      customerInfo={this.props.customerInfo}
      customerName={this.state.customerName}
      />
      <SaleInvoiceSummary grandTotal={this.props.grandTotal} />
      </rs.Row>
      </rs.Container>
      </React.Fragment>
      );
      }
      if (
      !this.props.productLoading &&
      !this.props.productError &&
      !this.props.error
      ) {
      console.log('Products have been loaded');
      sui = (
      <React.Fragment>
      <rs.Container fluid className={classes.gridContainer}>
      <LineItemsContainer />
      </rs.Container>
      </React.Fragment>
      );
      }
      return (
      <React.Fragment>
      {ui}
      {sui}
      </React.Fragment>


      );
      }

      }


      Customer.js (exluding imports)



      const Customer = props => {
      function _renderMenuItemChildren(option, props, index) {
      return [
      <Highlighter key="name" search={props.text}>
      {option.name}
      </Highlighter>,
      <div key="place">
      <small>Place: {option.place}</small>
      </div>,
      ];
      }
      return (
      <React.Fragment>
      {console.log(props.customerName)}
      <rs.Card col="sm-4" className={classes.firstCard}>
      <rs.CardHeader className={classes.cardHeader}>
      Customer Details
      </rs.CardHeader>
      <rs.CardBody className={classes.cardBodySaleInvoice}>
      <rs.Label>Name</rs.Label>
      <React.Fragment>
      <Typeahead
      className={classes.customerTypeahead}
      defaultInputValue={props.customerName}
      allowNew={true}
      newSelectionPrefix="Add New: "
      disabled={false}
      labelKey="name" // this determines what array key value to show
      multiple={false}
      options={props.customerData}
      placeholder="Choose a customer..."
      onBlur={event => props.onBlurCustomerName(event)}
      renderMenuItemChildren={_renderMenuItemChildren}
      />
      <rs.FormGroup />
      </React.Fragment>
      <div className={classes.customerCardBody}>
      <rs.Label>Address</rs.Label>
      <div className={classes.address}>
      {props.customerInfo.addressLineOne}
      <br />
      {props.customerInfo.addressLineTwo}
      <br />
      {props.customerInfo.address_line_three}
      <br />
      {props.customerInfo.contact_no_one}
      <br />
      {props.customerInfo.gst_number}
      <br />
      <button>Edit</button>
      </div>
      </div>
      </rs.CardBody>
      </rs.Card>
      </React.Fragment>
      );
      };


      (PS: I am new to React, additional comments/criticism regarding the code will be helpful)







      reactjs react-redux react-props






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 11 at 17:49

























      asked Nov 11 at 17:12









      Rounak Jain

      177




      177
























          1 Answer
          1






          active

          oldest

          votes

















          up vote
          0
          down vote













          I added a html input component and found that it worked correctly.
          The issue was with the Typeahead component.



          https://github.com/fmoo/react-typeahead/issues/74#issuecomment-112552406



          Also, now using react-select instead of Typeahead and that works correctly too.






          share|improve this answer





















            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53251178%2fchild-component-does-not-re-render-when-props-change%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            0
            down vote













            I added a html input component and found that it worked correctly.
            The issue was with the Typeahead component.



            https://github.com/fmoo/react-typeahead/issues/74#issuecomment-112552406



            Also, now using react-select instead of Typeahead and that works correctly too.






            share|improve this answer

























              up vote
              0
              down vote













              I added a html input component and found that it worked correctly.
              The issue was with the Typeahead component.



              https://github.com/fmoo/react-typeahead/issues/74#issuecomment-112552406



              Also, now using react-select instead of Typeahead and that works correctly too.






              share|improve this answer























                up vote
                0
                down vote










                up vote
                0
                down vote









                I added a html input component and found that it worked correctly.
                The issue was with the Typeahead component.



                https://github.com/fmoo/react-typeahead/issues/74#issuecomment-112552406



                Also, now using react-select instead of Typeahead and that works correctly too.






                share|improve this answer












                I added a html input component and found that it worked correctly.
                The issue was with the Typeahead component.



                https://github.com/fmoo/react-typeahead/issues/74#issuecomment-112552406



                Also, now using react-select instead of Typeahead and that works correctly too.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 12 at 4:23









                Rounak Jain

                177




                177






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.





                    Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                    Please pay close attention to the following guidance:


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53251178%2fchild-component-does-not-re-render-when-props-change%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Florida Star v. B. J. F.

                    Danny Elfman

                    Lugert, Oklahoma