道具更改时子组件不会重新呈现

时间:2018-11-11 17:12:25

标签: reactjs react-redux react-props

问题:

我的应用程序的第一页显示销售发票列表。

我选择一个运行以单击发票的ID作为参数的函数,并通过API调用获取其详细信息。

Customer渲染的

SaleInvoice组件具有一个输入框(“预定义”组件),该输入框应显示customerNameSaleInvoice传递而来,但操作不正确。有时为空白,当我返回首页(销售发票清单)并选择其他销售发票时,即先前销售发票的customerName。我检查了控制台日志(请参阅<React.Fragment>组件中Customer之后的行),并且在减速器显示的状态下可以看到customerName的正确值。

最初,SaleInvoice是有状态组件,但没有状态对象。我将状态设为通过componentWillMount中的API来获取数据。由于上述问题,我尝试了以下方法:

customerName的状态下添加了SaleInvoice

在客户道具中将this.props.customerName更改为this.state.customerName

已使用

  

getDerivedStateFromProps()

说我不能使用componentWillMount

还尝试了shouldComponentUpdate和其他一些东西。 什么都没有。请帮助。如果需要发布更多代码,请告诉我。

减速器的相关切片

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(不包括进口商品)

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(不包括进口商品)

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(不包括导入)

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:我是React的新手,对代码的其他评论/批评将很有帮助)

1 个答案:

答案 0 :(得分:0)

我添加了一个html输入组件,并发现它可以正常工作。 问题出在Typeahead组件上。

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

此外,现在使用react-select代替Typeahead,它也可以正常工作。