2017-02-14 52 views
2

編輯記錄時,組件上顯示的數據屬於道具。我得到一個錯誤編輯記錄:道具與狀態之間的衝突

警告:無法形式propType:您沒有onChange處理程序提供了一個value道具表單字段。這將呈現一個只讀字段。如果該字段應該是可變的,請使用defaultValue。否則,請設置onChangereadOnly。檢查TerritoryDetail的渲染方法。

我有一種感覺,我實現了我的編輯記錄組件錯誤的方式根據文檔說什麼涉及controlled components

編輯記錄時,你不應該爲字段值使用道具嗎?如果是這樣的話,我在應用程序狀態下有記錄的值,但是如何在不使用道具的情況下將我的應用程序狀態同步到組件狀態?

此外,道具說選擇選項應該在編輯上有什麼價值。但組件狀態用於監視選擇選項中的更改。當道具由應用程序狀態設置而不是組件狀態時,組件狀態如何更新記錄的道具?

import React, { Component } from 'react'; 
import { connect } from 'react-redux'; 
import { getTerritory, getTerritoryMetaData, updateTerritory, modal } from '../actions/index'; 
import { Link } from 'react-router'; 
import { reduxForm } from 'redux-form'; 
import TerritoryTabs from './territory-tabs'; 

class TerritoryDetail extends Component { 

    constructor(props) { 
    super(props); 


    this.openSearchUserQueueModal = this.openSearchUserQueueModal.bind(this); 
    this.setAssignedToType = this.setAssignedToType.bind(this); 
    this.onSubmit = this.onSubmit.bind(this); 
    } 
    componentWillMount() { 
    // console.log(this.props); 
    this.props.getTerritory(this.props.params.id); 
    this.props.getTerritoryMetaData(); 
    } 

    renderTerritoryPickList(fieldName) { 
    return this.props.territoryFields.map((territoryField) => { 
     const shouldRender = territoryField.name === fieldName; 
     if (shouldRender) { 
     return territoryField.picklistValues.map((option) => { 
      return<option value={option.value}>{option.label}</option>; 
     }); 
    } 
    }); 
    } 

    setAssignedToType(event) { 
    this.setState({ assignedToType : event.target.value }); 
    } 

    openSearchUserQueueModal(searchType) { 
    this.props.modal({ 
     type: 'SHOW_MODAL', 
     modalType: 'USER_QUEUE_SEARCH', 
     modalProps: {searchType} 
    }) 
    } 

    onSubmit() { 
    console.log('Update button being clicked'); 
    this.props.updateTerritory({ 
     Name: this.refs[ `Name`].value, 
     tpslead__Type__c: this.refs[ `tpslead__Type__c`].value, 
     tpslead__Assigned_To_Type__c: this.refs[ `tpslead__Assigned_To_Type__c`].value, 
     tpslead__Assigned_To__c: this.refs['tpslead__Assigned_To__c'].value, 
     tpslead__Assigned_To_ID__c: this.refs['tpslead__Assigned_To_ID__c'].value 
     }, this.props.params.id); 
    } 

    onChangeTerritoryName(event) { 
    this.props. 
    } 

    render() { 
    if(!this.props.territory) { 
     return <div>Loading...</div>; 
    } 

    return(
     <TerritoryTabs id={this.props.params.id} listTab="detail"> 
     <div className="slds-form"> 
       <div className="slds-form-element"> 
      <div className="slds-form-element__label"> 
        <label className="slds-align-middle" htmlFor="input1">Lead Territory Name</label> 
      </div> 
      <div className="slds-form-element__control"> 
        <input type="text" ref="Name" className="slds-input" value={this.props.territory.Name}/> 
      </div> 
      </div> 
       <div className="slds-form-element"> 
       <label className="slds-form-element__label" htmlFor="input2">Type</label> 
       <div className="slds-form-element__control"> 
        <div className="slds-select_container"> 
         <select ref="tpslead__Type__c" className="slds-select" value={this.props.territory.tpslead__Type__c}> 
        <option></option> 
        {this.renderTerritoryPickList('tpslead__Type__c')} 
         </select> 
        </div> 
       </div> 
       </div> 
       <div className="slds-form-element"> 
       <label className="slds-form-element__label" htmlFor="input3">Assigned to Type</label> 
       <div className="slds-form-element__control"> 
        <div className="slds-select_container"> 
         <select ref="tpslead__Assigned_To_Type__c" onChange={ this.setAssignedToType } className="slds-select" value={this.props.territory.tpslead__Assigned_To_Type__c}> 
          <option></option> 
        {this.renderTerritoryPickList('tpslead__Assigned_To_Type__c')} 
         </select> 
        </div> 
       </div> 
       </div> 
       <div className="slds-form-element"> 
       <label className="slds-form-element__label">Assigned To</label> 
       <div className="slds-form-element__control"> 
       <section className="slds-clearfix"> 
       <input ref="tpslead__Assigned_To__c" value={this.props.territory.tpslead__Assigned_To__c} className="slds-input slds-float--left" style={{maxWidth: '95%'}} disabled/> 
       <input ref="tpslead__Assigned_To_ID__c" value={this.props.territory.tpslead__Assigned_To_ID__c} type="hidden" /> 
       <button onClick={this.openSearchUserQueueModal.bind(this, this.props.territory.tpslead__Assigned_To_Type__c)} className="slds-button slds-button--icon-border slds-float--right" aria-live="assertive" style={{display: 'inline'}}> 
       <svg className="slds-button__icon" aria-hidden="true"> 
        <use xlinkHref={searchIcon}></use> 
       </svg> 
       </button> 
       </section> 
       </div> 
       </div> 
       <div className="slds-form-element slds-p-top--small"> 
      <Link to="/" className="slds-button slds-button--neutral"> 
       Cancel 
      </Link> 
       <button type="button" onClick={this.onSubmit} className="slds-button slds-button--brand">Update</button> 
       </div> 
     </div> 
     </TerritoryTabs> 
    ); 
    } 
} 

function mapStateToProps(state) { 
console.log(state); 

    return { territory: state.territories.single, 
      territoryFields: state.territories.fields 
     }; 

} 

export default connect(mapStateToProps, { getTerritoryMetaData, getTerritory, updateTerritory, modal })(TerritoryDetail); 

回答

4

受控組件意味着您提供了一個值和一個onChange處理程序。你必須有兩個,或者React會抱怨。如果您通過nullundefined值,這也是正確的,因此您需要在這些情況下默認爲空字符串。例如:

export function TerritorySelect({ territory = '', options, onChange }) { 
    const choices = options.map((o, i) => (
    <option key={i} value={o.value}>{o.label}</option> 
)); 

    const update = e => onChange(e.target.value); 

    return (
    <select value={territory} onChange={update}> 
     {choices} 
    </select> 
); 
} 

export default connect(
    state => ({ territory: state.territory.get('territory') }), 
    { onChange: actions.updateTerritory } 
)(TerritorySelect) 
0

黃金法則是,如果數據將被用戶輸入改變,然後使用狀態,否則使用道具。爲了避免應用程序狀態和組件狀態混淆,我將調用應用程序狀態Redux存儲。

您可以將您的Redux存儲中的任何內容與您已具有的功能mapStateToProps以及組件的構造函數簡單地設置爲狀態。但道具總是需要的,只是不像你使用它的方式。要做到這一點在類的構造方法,只需增加以下內容:

this.state = { 
    // whatever you want to define goes here 
    // if you want to pass props you don't need to call this, just props.foo 
} 

這意味着,你可以處理你的選擇的狀態,您輸入的狀態沒有問題。

只要他們沒有收到用戶交互,您的道具每當他們收到新道具時都會更新。這意味着你可以使用你的Redux商店來分派行動,什麼會向你的道具發起更新。