我有一个列表组件,它可以获取数据并将结果映射到类似卡片的子组件上,以创建“卡片”列表。以下是一个例子:
class Card extends Component {
constructor(props) {
super(props);
this.state = {
activeTab: 1
};
}
setActiveTab = (activeTab) => {
this.setState({ activeTab });
}
render() {
const activeTab = this.state.activeTab;
return (
<div className="card">
<ul className="nav nav-tabs card-header-tabs">
<li
className="nav-item"
key={ 1 }
onClick={ () => this.setActiveTab(1) }
>
<a className="nav-link" href="#">Overview</a>
</li>
<li
className="nav-item"
key={ 2 }
onClick={ () => this.setActiveTab(2) }
>
<a className="nav-link" href="#">Data</a>
</li>
<li
className="nav-item"
key={ 3 }
onClick={ () => this.setActiveTab(3) }
>
<a className="nav-link" href="#">Edit</a>
</li>
</ul>
<h3 className="card-title">{ this.props.title }</h3>
{ activeTab === 1 &&
<h5 className="card-text">
{ this.props.body }
</h5>
}
{ activeTab === 2 &&
<div className="card-data">
<a>Yes: { this.props.yes }</a>
<a>No: { this.props.no }</a>
</div>
}
{ activeTab === 3 &&
<div>
<a
href="/cards"
onClick={ this.props.onDelete }
className="delete-card"
>
Delete
</a>
</div>
}
</div>
)
}
}
export default Card;
class CardList extends Component {
componentDidMount() {
this.props.fetchCards();
}
renderCards() {
return this.props.cards.reverse().map(({ _id, title, body, yes, no }) => {
return (
<Card
key={_id}
title={title}
body={body}
yes={yes}
no={no}
onDelete={() => this.props.deleteSurvey(_id)}
/>
);
});
}
render() {
return (
<div className="container">
<div className="row">{this.renderCards()}</div>
</div>
);
}
}
每张卡都有标签,单击标签可确定每张特定卡片中显示的文字。选项卡/切换功能正常,但我的问题是单击选项卡时整个列表会重新呈现。因此,如果您位于列表的底部,则重新渲染会将您带回到列表的顶部。
我尝试过实现componentShouldUpdate,但到目前为止还没有成功。我想要卡片切换它的内容,列表仍然存在。使用shouldUpdate生命周期方法是否正确?还是有更好的方法?
答案 0 :(得分:2)
我认为这是prbolem
onClick={ () => this.setActiveTab(2) }
基本上,React
决定在组件状态或道具中检测到change
时重新渲染组件,并且它只对对象进行浅层比较。
在使用闭包时,每次调用Card
组件渲染函数时都会动态地重新创建这些函数。 React检测传递给li
元素的新对象(在JS中,函数被视为对象),然后重绘它。
要解决此问题,您可以执行以下操作:
<li className="nav-item" data-tab={ 1 }
onClick={this.navLinkClickHandler}>
<a className="nav-link" href="#">Overview</a>
</li>
然后在您的组件中定义navLinkClickHandler
:
navLinkClickHandler = (evt) => this.setState({activeTab: evt.target.dataset.tab})
有关React reconcilation的更多信息,请点击此处:
https://reactjs.org/docs/reconciliation.html
关于在渲染函数中使用闭包:
https://reda-bx.gitbooks.io/react-bits/content/conventions/08.closures-in-render.html
答案 1 :(得分:2)
在<a>
锚标记中,您有 href =&#34;#&#34; `这将始终将您重定向到新的链接。 (#将重定向到当前页面重新渲染所有内容)。
最简单的解决方案是删除href =&#34;#&#34; ,这会删除您的
cursor: pointer;
样式,但您可以重新添加回到你的nav-item
classname。
另一个简单的解决方案是您可以将 onClick 移动到锚标记并添加 evt.preventDefault()(这会阻止事件处理程序从执行默认操作,将页面加载到href)然而,这将使您必须单击锚标记,以便在<li>
和{{之间填充1}}这可能不是你最好的解决方案。
<a>
然而,Thai Duong Tran提出了一个很好的观点,你不想每次都重新创建这个功能。
最佳解决方案是将您的匿名函数移动到类函数中。 (此解决方案还会删除href =&#34;#&#34;因此如果您需要该样式,则需要将
<li className="nav-item" key={ 3 } > <a className="nav-link" href="#" onClick={ (e) => { e.preventDefault(); this.setActiveTab(3); } } > Edit </a> </li>
添加到您的CSS中
cursor: pointer;
你的删除操作也有同样的问题,你添加了一个href =&#34; / card&#34;所以你要小心。
如果您希望将路线操作移至不同的网页/网址。您应该考虑添加 <li
className="nav-item"
data-tab={ 1 }
onClick={this.onNavClick}
>
<a className="nav-link">Overview</a>
</li>
onNavClick = (evt) => {
this.setState({activeTab: evt.target.dataset.tab});
}
答案 2 :(得分:0)
在CARD组件中尝试此代码(如果您尚未尝试过)。可能工作正常。
shouldComponentUpdate(nextProps,nextState){
if(this.state.activeTab === nextState.activeTab ){
return false
} else {
return true
}
}