componentDidUpdate(){//wondering if I should do this inside compoentWillRecieveProps???
const { match: { params } } = this.props;
//console.log(this.props.selectBook)
if(typeof this.props.selectBook !== 'undefined'){
if(this.state.changedItem !== this.props.goToBook ){
this.props.selectBook(params.bookID);
//this.setState({changedItem: params.bookID}); Want to change state here, but cannot do this because I am in componentDidUpdate
}
}
}
问题是如果我取消注释控制台,它会持续运行,因为它会看到selectBook不断被调用。所以我需要以某种方式检查selectBook prop并确保它没有改变。任何有关这方面的帮助将不胜感激。
--- ORIGINAL MESSAGE ---所以我有以下代码:
class ArrayList extends React.Component {
constructor(props){
super(props);
this.state = {
};
this.createListItem = this.createListItem.bind(this);
this.handleDelete = this.handleDelete.bind(this);
this.getCollection = this.getCollection.bind(this);
}
render () {
return (
<ul className="user-list">
{this.props.items.map(this.createListItem)}
</ul>
);
}
createListItem(item) {
if(item.id){
return (
<li key={item.id }>
{item.name}
{this.props.isEditing ? <Button className="deleteMe" onClick={this.handleDelete(this, item)}>Delete</Button> :''}
</li>
);
}else if(item.AwardKey) {
return (
<li key={item.AwardKey }>
{item.Award}{item.AwardYear?'-':''}{item.AwardYear}
{this.props.isEditing ? <Button className="deleteMe" onClick={this.handleDelete(this, item)}>Delete</Button> :''}
</li>
);
}else if(item.RelBookUseInKey) {
return (
<li key={item.RelBookUseInKey }>
{this.getCollection(item.CollectionForUseInKey)}{item.CollectionNumber?'-':''}{item.CollectionNumber}{item.Rating?'-':''}{item.Rating}{item.RelBookUseInKey}
{this.props.isEditing ? <Button className="deleteMe" onClick={this.handleDelete(this, item)}>Delete</Button> :''}
</li>
);
}else if(item.RelBookDoNotUseInKey){
return (
<li key={item.RelBookDoNotUseInKey }>
{this.getCollection(item.CollectionForUseInKey)}{item.CollectionNumber && item.item.CollectionForUseInKey?'-':''}{item.CollectionNumber}{item.Rating?'-':''}{item.Rating}{item.RelBookDoNotUseInKey}
{this.props.isEditing ? <Button className="deleteMe" onClick={this.handleDelete(this, item)}>Delete</Button> :''}
</li>
);
}
}
getCollection(collectionVal){
if(!collectionVal) return '';
let obj = this.props.collection.find((x)=>{
return x.value === collectionVal
});
return obj.label;
}
handleDelete(e){
if(this.props.handleDelete) {
this.props.handleDelete(e);
}
}
}export default ArrayList;
这个表现部分不断呈现并且不会停止。我知道这是因为我在我的渲染前面放了一个console.log,它不断运行,减慢了我的处理器速度。有没有办法让一个演示组件只在道具改变时渲染?我认为这是反应/减少的重点。我想我可能会对这个组件设置错误。就像redux工作流程可能正在更新触发此组件重新渲染的内容。所以我想知道这个组件的生命周期是否依赖于其父数据来改变?
关于这个组件试图做什么:我希望将一个数组传递给它,并根据数组的内容创建一个不同类型的数组构建器。一些数组构建器具有不同类型的表单元素,以向数组添加不同的项。 这是父组件:
class ArrayValuesEdit extends React.Component {
constructor(){
super();
this.state = {
displayText: '',
displayObj:{},
displayArray:[],
isEditing: false,
newItem:0,
checkProps:false,
entryType: 'singleText'
};
this.onClickEdit = this.onClickEdit.bind(this);
this.handleSingleSaveEdit = this.handleSingleSaveEdit.bind(this);
this.handleAwardSaveEdit = this.handleAwardSaveEdit.bind(this);
this.handleUseInSaveEdit = this.handleUseInSaveEdit.bind(this);
this.handleDoNotSaveEdit = this.handleDoNotSaveEdit.bind(this);
this.handleTextChanged = this.handleTextChanged.bind(this);
this.handleMultipleTextChanged = this.handleMultipleTextChanged.bind(this);
this.handleKeyPress = this.handleKeyPress.bind(this);
this.renderList = this.renderList.bind(this);
this.onSelectionHandle = this.onSelectionHandle.bind(this);
this.bindSelectionHandle = this.bindSelectionHandle.bind(this);
this.handleDelete = this.handleDelete.bind(this);
this.drawEntryType = this.drawEntryType.bind(this);
}
componentDidMount(){
if(typeof this.props.display !== 'undefined' && typeof this.props.displayArray !== 'undefined'){
let result = this.props.options.find(x => x.value === this.props.val);
const displayText = result.text;
this.setState( {displayText} );
}
}
componentWillReceiveProps(nextProps) {
// You don't have to do this check first, but it can help prevent an unneeded render
if (nextProps.displayArray !== this.state.displayArray && !this.state.checkProps) {
this.setState({ displayArray: nextProps.displayArray, isEditingAll: nextProps.isEditingAll, readOnly: nextProps.readOnly, checkProps: true });
}
if (nextProps.entryType !== this.state.entryType)this.setState({entryType: nextProps.entryType});
}
onClickEdit(){
this.setState({isEditing: !this.state.isEditing});
}
handleUseInSaveEdit(){
let newObj = {RelBookUseInKey:this.state.newItem, CollectionForUseInKey: this.state.displayObj.CollectionForUseInKey, CollectionNumber: this.state.displayObj.CollectionNumber, Rating: this.state.displayObj.Rating};
//this.props.handleSingleSaveEdit();
console.log(newObj);
let newState = update(this.state, {newItem: {$apply: function(x) {return x +1;}}, isEditing:{$set:false}, displayArray:{$push: [newObj]}});
this.setState(newState, ()=>{console.log(this.state)});
}
handleDoNotSaveEdit(){
let newObj = {RelBookDoNotUseInKey:this.state.newItem, CollectionForUseInKey: this.state.displayObj.CollectionForUseInKey, CollectionNumber: this.state.displayObj.CollectionNumber, Rating: this.state.displayObj.Rating};
//this.props.handleSingleSaveEdit();
let newState = update(this.state, {newItem: {$apply: function(x) {return x +1;}}, isEditing:{$set:false}, displayArray:{$push: [newObj]}});
this.setState(newState);
}
handleAwardSaveEdit(){
let newObj = {AwardKey:this.state.newItem, Award: this.state.displayObj.Award, AwardYear: this.state.displayObj.AwardYear};
//this.props.handleSingleSaveEdit();
let newState = update(this.state, {newItem: {$apply: function(x) {return x +1;}}, isEditing:{$set:false}, displayArray:{$push: [newObj]}});
this.setState(newState);
}
handleSingleSaveEdit(){
let newObj = {id:this.state.newItem, name: this.state.displayText};
//this.props.handleSingleSaveEdit();
let newState = update(this.state, {newItem: {$apply: function(x) {return x +1;}}, isEditing:{$set:false}, displayArray:{$push: [newObj]}});
this.setState(newState);
}
handleTextChanged(e){
//this.props.handleTextChanged();
this.setState({displayText: e.target.value});
}
handleMultipleTextChanged(e){
//this.props.handleTextChanged();
this.setState({displayObj: {...this.state.displayObj, [e.target.name]:e.target.value}});
}
handleDropSelectChange(value, name){
this.setState({displayObj: {...this.state.displayObj, [name]:value}});
}
handleKeyPress() {
//this.props.handleKeyPress();
this.setState({isEditing: !this.state.isEditing});
};
onKeyPress(){
if(event.charCode === 13 && this.props.onKeyPress){
this.onKeyPress(event);
}
}
handleDelete(e){
}
onSelectionHandle( buttonText ) {
this.setState({displayText: buttonText});
}
bindSelectionHandle( buttonText ) {
return this.onSelectionHandle.bind( this, buttonText )
}
drawEntryType(){
if(this.state.entryType === 'singleText'){
return <InputContainer className="inputElem" onSaveEdit={this.handleSingleSaveEdit} onKeyPress={this.handleKeyPress} onTextChanged={this.handleTextChanged}/>
}else if (this.state.entryType === 'awards'){
return (
<div>
Award:<input name="Award" className="inputValue" value={this.state.displayObj.Award || ''} type="text" onKeyPress={this.onKeyPress} onChange={this.handleMultipleTextChanged}/>
Year:<input name="AwardYear" className="inputValue" value={this.state.displayObj.AwardYear || ''} type="text" onKeyPress={this.onKeyPress} onChange={this.handleMultipleTextChanged}/>
<button className="saveMe" onClick={this.handleAwardSaveEdit}>Save</button>
</div>)
}else if (this.state.entryType === 'usein'){
return (<div>
Collection:<Select
closeOnSelect={true}
disabled={false}
multi={false}
onChange={(val) => this.handleDropSelectChange(val, "CollectionForUseInKey")}
options={this.props.collectionOptions}
placeholder='Select Collection'
removeSelected={false}
rtl={false}
simpleValue
value={this.state.displayObj.CollectionForUseInKey}
/>
Collection Number:<input name="CollectionNumber" className="inputValue" value={this.state.displayObj.CollectionNumber || ''}
type="text" onKeyPress={this.onKeyPress} onChange={this.handleMultipleTextChanged}/>
Rating:<Select
closeOnSelect={true}
disabled={false}
multi={false}
onChange={(val) => this.handleDropSelectChange(val, "Rating")}
options={this.props.ratingOptions}
placeholder='Select Rating'
removeSelected={false}
rtl={false}
simpleValue
value={this.state.displayObj.Rating}
/>
<button className="saveMe" onClick={this.handleUseInSaveEdit}>Save</button>
</div>)
}else if (this.state.entryType === 'donot'){
return (
<div>
Collection:<Select
closeOnSelect={true}
disabled={false}
multi={false}
onChange={(val) => this.handleDropSelectChange(val, "Collection")}
options={this.props.collectionOptions}
placeholder='Select Collection'
removeSelected={false}
rtl={false}
simpleValue
value={this.state.displayObj.Collection}
/>
Reason:<input name="Reason" className="inputValue" value={this.state.displayObj.Reason || ''}
type="text" onKeyPress={this.onKeyPress} onChange={this.handleMultipleTextChanged}/>
<button className="saveMe" onClick={this.handleDoNotSaveEdit}>Save</button>
</div>)
}else if (this.state.entryType === 'license'){
return (<div>
</div>)
}
}
renderList(){
if (typeof this.state.displayArray === "undefined"){
return;
} else if(this.state.displayArray){
return this.state.displayArray.map((option)=>{
return(
<Button eventKey={option.value} onClick={ this.bindSelectionHandle( option.text )}>{option.text}</Button>
);
});
}
}
render(){
return(
<div className="display-choices">
{this.state.isEditing ? this.drawEntryType() :''}
<span className="clickMe" onClick={this.onClickEdit}><ArrayList collection={this.props.collectionOptions || []} items={this.state.displayArray} isEditing={this.state.isEditing} /> </span>
</div>
)
}
}export default ArrayValuesEdit;
我还有以下连接的redux组件,它包含ArrayValuesEdit组件。为了保持代码简短,我将删除我为它编写的jsx,这不适用于重新渲染的原因。
export class BookDetail extends Component{
componentDidMount(){
Moment.locale('en');
momentLocalizer();
}
componentWillReceiveProps(nextProps) {
if(typeof this.props.getAbeReadingLevelOptions !== 'undefined')this.props.getAbeReadingLevelOptions();
if(typeof this.props.getAgeAppropriateOptions !== 'undefined')this.props.getAgeAppropriateOptions();
if(typeof this.props.getAgeOptions !== 'undefined')this.props.getAgeOptions();
if(typeof this.props.getBindingTypeOptions !== 'undefined')this.props.getBindingTypeOptions();
if(typeof this.props.getCitationOptions !== 'undefined')this.props.getCitationOptions();
if(typeof this.props.getCollectionOptions !== 'undefined')this.props.getCollectionOptions();
if(typeof this.props.getCultureOptions !== 'undefined')this.props.getCultureOptions();
if(typeof this.props.getDistrictApprovalOptions !== 'undefined')this.props.getDistrictApprovalOptions();
if(typeof this.props.getEthnicityOptions !== 'undefined')this.props.getEthnicityOptions();
if(typeof this.props.getFormatOptions !== 'undefined')this.props.getFormatOptions();
if(typeof this.props.getGenderOptions !== 'undefined')this.props.getGenderOptions();
if(typeof this.props.getGuidedReadingLevelOptions !== 'undefined')this.props.getGuidedReadingLevelOptions();
if(typeof this.props.getIsbnSeparationStatusOptions !== 'undefined')this.props.getIsbnSeparationStatusOptions();
if(typeof this.props.getLexileCodeOptions !== 'undefined')this.props.getLexileCodeOptions();
if(typeof this.props.getNarratorOptions !== 'undefined')this.props.getNarratorOptions();
if(typeof this.props.getPrimaryGenreOptions !== 'undefined')this.props.getPrimaryGenreOptions();
if(typeof this.props.getRatingOptions !== 'undefined')this.props.getRatingOptions();
if(typeof this.props.getSecondaryGenreOptions !== 'undefined')this.props.getSecondaryGenreOptions();
if(typeof this.props.getSensitiveContentOptions !== 'undefined')this.props.getSensitiveContentOptions();
if(typeof this.props.getCountryOptions !== 'undefined')this.props.getCountryOptions();
}
componentDidUpdate(){
const { match: { params } } = this.props;
if(typeof this.props.selectBook !== 'undefined'){
if(this.state.changedItem !== this.props.goToBook ){
this.props.selectBook(params.bookID);
this.state.changedItem = params.bookID;
}
}
}
constructor(){
super();
this.state = {
isEditingAll: false,
displayMeta:false,
displayISBN:false,
displayPrice:false,
displayOps:false,
displayLevel:false,
displayTrain:false,
displayAppro:false,
displayLang:false,
displayNYC:false,
displayNotes:false,
displayTopics:false,
changedItem:0
};
this.onClickMeta = this.onClickMeta.bind(this);
this.onClickISBN = this.onClickISBN.bind(this);
this.onClickPrice = this.onClickPrice.bind(this);
this.onClickOps = this.onClickOps.bind(this);
this.onClickLevel = this.onClickLevel.bind(this);
this.onClickTrain = this.onClickTrain.bind(this);
this.onClickAppro = this.onClickAppro.bind(this);
this.onClickLang = this.onClickLang.bind(this);
this.onClickNYC = this.onClickNYC.bind(this);
this.onClickNotes = this.onClickNotes.bind(this);
this.onClickTopics = this.onClickTopics.bind(this);
this.onImgError = this.onImgError.bind(this);
this.removeSpaces = this.removeSpaces.bind(this);
this.onCheckChanged = this.onCheckChanged.bind(this);
}
onClickMeta(){this.setState({displayMeta: !this.state.displayMeta});}
onClickISBN(){this.setState({displayISBN: !this.state.displayISBN});}
onClickPrice(){this.setState({displayPrice: !this.state.displayPrice});}
onClickOps(){this.setState({displayOps: !this.state.displayOps});}
onClickLevel(){this.setState({displayLevel: !this.state.displayLevel});}
onClickTrain(){this.setState({displayTrain: !this.state.displayTrain});}
onClickAppro(){this.setState({displayAppro: !this.state.displayAppro});}
onClickLang(){this.setState({displayLang: !this.state.displayLang});}
onClickNYC(){this.setState({displayNYC: !this.state.displayNYC});}
onClickNotes(){this.setState({displayNotes: !this.state.displayNotes});}
onClickTopics(){this.setState({displays: !this.state.displayNotes});}
onImgError(e) {
e.target.src = '/img/NoImageFound240px.jpg';
}
removeSpaces(val){
return val.replace(/^\s+|\s+$/g,'');
}
onCheckChanged(e){
let newVal;
{e.target.checked ? newVal = 1 : newVal = 0};
newVal === 1 ? this.setState({isEditingAll: true}) : this.setState({isEditingAll: false});
this.setState({isEditingAll: newVal});
}
render(){
const YES_NO = [{"value":-1, "label":"N/A"},{"value":0, "label":"No"},{"value":1, "label":"Yes"}];
if(!this.props.book){
return <div>Select a book to get started.</div>;
}
return(
......jsx is added here.....
)
}
}
function mapDispatchToProps(dispatch){
return{
getAbeReadingLevelOptions: bindActionCreators(actions.getAbeReadingLevelOptions, dispatch),
getAgeAppropriateOptions: bindActionCreators(actions.getAgeAppropriateOptions, dispatch),
getAgeOptions: bindActionCreators(actions.getAgeOptions, dispatch),
getBindingTypeOptions: bindActionCreators(actions.getBindingTypeOptions, dispatch),
getCitationOptions: bindActionCreators(actions.getCitationOptions, dispatch),
getCollectionOptions: bindActionCreators(actions.getCollectionOptions, dispatch),
getCultureOptions: bindActionCreators(actions.getCultureOptions, dispatch),
getDistrictApprovalOptions: bindActionCreators(actions.getDistrictApprovalOptions, dispatch),
getEthnicityOptions: bindActionCreators(actions.getEthnicityOptions, dispatch),
getFormatOptions: bindActionCreators(actions.getFormatOptions, dispatch),
getGenderOptions: bindActionCreators(actions.getGenderOptions, dispatch),
getGuidedReadingLevelOptions: bindActionCreators(actions.getGuidedReadingLevelOptions, dispatch),
getIsbnSeparationStatusOptions: bindActionCreators(actions.getIsbnSeparationStatusOptions, dispatch),
getLexileCodeOptions: bindActionCreators(actions.getLexileCodeOptions, dispatch),
getNarratorOptions: bindActionCreators(actions.getNarratorOptions, dispatch),
getPrimaryGenreOptions: bindActionCreators(actions.getPrimaryGenreOptions, dispatch),
getRatingOptions: bindActionCreators(actions.getRatingOptions, dispatch),
getSecondaryGenreOptions: bindActionCreators(actions.getSecondaryGenreOptions, dispatch),
getSensitiveContentOptions: bindActionCreators(actions.getSensitiveContentOptions, dispatch),
selectBook: bindActionCreators(bookActions.selectBook, dispatch),
getCountryOptions: bindActionCreators(getCountryOptions, dispatch)
}
}
function mapStateToProps(state){
return{
options: state.options,
book: state.activeBook,
goToBook: state.goToBook
};
}
export default connect(mapStateToProps, mapDispatchToProps)(BookDetail);
答案 0 :(得分:1)
很可能是因为你在渲染中绑定它。每次为外部函数调用render时,这不仅会在运行时创建多个函数对象实例。如果Button是一个Pure组件,它应该是最有可能的,每次重新渲染Button时,它将为onClick创建一个新的函数对象引用,因为Buttons prop正在改变,因为它的引用是它将重新渲染
onClick={this.handleDelete.bind(this, item)} //bad practice
在下面做,这将确保所有onClick引用一个在构造函数中绑定的函数对象引用,从而使您的组件更高效。
Constructor(){
this.handleDelete= this.handleDelete.bind(this)
}
//bind it once use every where
onClick={this.handleDelete}
并删除onClicks中的绑定。
答案 1 :(得分:0)
我使用componentDidMount和componentWillReceiveProps的混合来修复它,以确定是否命中了新路由并且是否设置了redux selectBook。似乎现在正在工作,没有不断刷新。