繁体   English   中英

根据父组件的状态来突变子组件,而无需重新渲染

[英]Mutating child components based on parent component's state, without re-rendering

目标

我正在尝试从父组件管理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元素上。


我如何以不同的方式构造它,以便:

  1. 子元素的道具无需重新渲染即可更新,或者
  2. jQuery集合参考没有改变

我真的很想避免每次组件更新时都得到一个新的jQuery集合。

悬停行为应仅限于单独的列表组件,而不是集合组件。

Collections组件保持当前悬停的项目的状态时,最好将处理程序作为prop的一部分传递,然后根据Collections组件设置的状态更改再次呈现列表。

如有必要,请使用基于React的事件处理程序,以使其成为受控组件。 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>
    )
  }
}

馆藏

import React from 'react'

export default class CollectionComponent extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      results: this.props.results,
      hoveredId: null
    }
  }

  onMouseEnter({ listingId }) {
       this.setState({ listingId });
  }
  onMouseLeave() {
       this.setState({ listingId: null });
  }

  render() {
    const {results, IndividualResult, perPage, options} = this.props

    return (
      <div className="paginated-results">
        {this.state.results.map( result =>  
          <IndividualResult key={result.id} hoveredId={this.state.hoveredId} result={result} options={options} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}/> 
        )}
      </div>
    )
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM