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)
reactjs react-redux react-props
add a comment |
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)
reactjs react-redux react-props
add a comment |
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)
reactjs react-redux react-props
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
reactjs react-redux react-props
edited Nov 11 at 17:49
asked Nov 11 at 17:12
Rounak Jain
177
177
add a comment |
add a comment |
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.
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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.
add a comment |
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.
add a comment |
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.
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.
answered Nov 12 at 4:23
Rounak Jain
177
177
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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