2017-02-14 49 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商店来分派行动,什么会向你的道具发起更新。