簡體   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