目标
我正在尝试从父组件管理mouseenter和mouseleave事件,以获取不断重新呈现的子组件的集合。
我正在为清单的集合构建一个可重用的组件,它可以执行诸如分页和在清单悬停时的其他一些功能。
因此,要使其可重复使用,我必须维护父级CollectionComponent
悬停的列表的状态,并根据父级的状态对每个单独的列表组件进行突变。
代码
这是我正在使用的组件(我将它们剥离为最基本的形式):
列表组件:
import React from 'react'
import $ from 'jquery'
import CollectionComponent from './CollectionComponent'
import Listing from './Listing'
export default class Listings extends React.Component {
constructor(props) {
super(props)
this.state = {
listings: this.props.listings,
}
}
render() {
return (<section className="listing-results">
{this.state.listings.map( listing =>
<CollectionComponent results={this.state.listings} IndividualResult={Listing} perPage={this.props.perPage} options={options}/>
)}
</section>)
}
}
集合组件:
import React from 'react'
export default class CollectionComponent extends React.Component {
constructor(props) {
super(props)
this.state = {
results: this.props.results,
hoveredId: null
}
}
componentDidMount() {
this.$listings = $('.result-card')
$(this.$listings).mouseenter(this.toggleInfoIn).mouseleave(this.toggleInfoOut)
}
toggleInfoIn = e => {
var { target } = e
var infoId = $(target).data('id')
this.setState({hoveredId: infoId})
}
toggleInfoOut = e => {
this.setState({hoveredId: null})
}
render() {
const {results, IndividualResult, perPage, options} = this.props
return (
<div className="paginated-results">
{this.state.results.map( result =>
<IndividualResult key={result.id} result={result} options={options}/>
)}
</div>
)
}
}
单个列表组件:
import React from 'react'
export default class Listing extends React.Component {
constructor(props) {
super(props)
}
render() {
const { listing, hoveredId } = this.props
return (
<div className="result-card" data-id={listing.id}>
<div className={hoveredId === listing.id ? 'hovered' : ''}>
Listing Content
</div>
</div>
)
}
}
我知道我可以用更高阶的组件来构造CollectionComponent
,使它更整洁,但是一旦我可以在基本设置下正常工作,我将把它留待以后重构。
问题
我的问题是,每次我悬停并更改父组件的状态时,它都会重新渲染子组件,因为它们的道具取决于父组件的状态。一旦发生这种情况,对我的jQuery清单集合的引用将不再有效。因此,鼠标事件会附加到不再存在的旧DOM元素上。
我该如何以不同的方式构造它,以便:
我真的想避免每次组件更新时都获得新的jQuery集合。
答案 0 :(得分:2)
悬停行为应仅限于单独的列表组件,而不是集合组件。
由于Collections
组件保持当前悬停的物品的状态,因此最好将处理程序作为prop的一部分传递,然后根据{{1}设置的状态变化再次呈现列表}组件。
在必要时使用基于反应的事件处理程序,这使它成为受控组件。将状态放在Collections
中不是个好主意,反应可以为您处理状态。
列表
DOM
收藏集
import React from 'react'
export default class Listing extends React.Component {
constructor(props) {
super(props);
this.onMouseEnter = this.onMouseEnter.bind(this);
this.onMouseLeave = this.onMouseLeave.bind(this);
}
onMouseEnter() {
this.props.onMouseEnter({ listingId: this.props.listing.id });
}
onMouseLeave() {
this.props.onMouseLeave();
}
render() {
const { listing, hoveredId } = this.props
const listingId = listing.id;
const isHovered = this.props.hoveredId === listing.id;
return (
<div className="result-card" onMouseEnter={this.onMouseEnter} onMouseLeave={onMouseLeave}>
<div className={isHovered ? 'hovered' : ''}>
Listing Content
</div>
</div>
)
}
}