简体   繁体   English

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

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

Goal 目标

I'm trying to manage mouseenter and mouseleave events from a parent component, for a collection of child components that keep getting re-rendered. 我正在尝试从父组件管理mouseenter和mouseleave事件,以获取不断重新呈现的子组件的集合。

I'm building a reusable component for the collection of listings, that does several things like pagination, and a few other things when a listing is hovered. 我正在为清单的集合构建一个可重用的组件,它可以完成诸如分页之类的几项工作,以及在悬停清单时执行的其他一些工作。

So to make this reusable, I have to maintain the state of the hovered listing from the parent CollectionComponent , and mutate each individual listing component based on the state of the parent. 因此,要使其可重用,我必须维护父CollectionComponent悬停列表的状态,并根据父状态对每个单独的列表组件进行突变。


Code

Here are the components I'm using (I stripped them all down to their most basic forms): 这是我正在使用的组件(我将它们剥离为最基本的形式):

Listings Component: 列表组件:

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>)
  }
}

Collection Component: 收集组件:

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>
    )
  }
}

Individual Listing Component: 个别列表组件:

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>
    )
  }
}

I know I can probably structure the CollectionComponent a little cleaner with a higher order component, but I'll leave that for refactoring later once I get it working properly with this basic setup. 我知道我可以用更高阶的组件来构造一个更干净的CollectionComponent ,但是一旦我在基本设置中正常使用它,我将把它留待以后重构。


Problem 问题

My problem is that every time I hover and change the state of the parent component, it re-renders the child components, because their props are dependent on the parent's state. 我的问题是,每次我悬停并更改父组件的状态时,它都会重新渲染子组件,因为它们的道具取决于父组件的状态。 Once this happens, the reference to my jQuery collection of listings is no longer valid. 一旦发生这种情况,对我的jQuery清单集合的引用将不再有效。 So the mouse events are attached to old DOM elements that no longer exist. 因此,鼠标事件将附加到不再存在的旧DOM元素上。


How can I structure this differently, so that either: 我如何以不同的方式构造它,以便:

  1. the child elements' props update without re-rendering, or 子元素的道具无需重新渲染即可更新,或者
  2. the jQuery collection reference doesn't change jQuery集合参考没有改变

I'd really like to avoid getting a new the jQuery collection every time the component updates. 我真的很想避免每次组件更新时都得到一个新的jQuery集合。

The behavior of hover should be confined to the individual listing component and not the Collections component. 悬停行为应仅限于单独的列表组件,而不是集合组件。

As the Collections component maintains the state of currently hovered item, it is good idea to pass an handler as part of props and then render the list again based on the change in state set by the Collections component. Collections组件保持当前悬停的项目的状态时,最好将处理程序作为prop的一部分传递,然后根据Collections组件设置的状态更改再次呈现列表。

Use react based event handlers where ever necessary which makes it for a controlled component. 如有必要,请使用基于React的事件处理程序,以使其成为受控组件。 It is not a good idea to put state in the DOM where react can take care of it for you. DOM中放置状态不是一个好主意,反应可以为您处理状态。

Listings 清单

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>
    )
  }
}

Collections 馆藏

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.

相关问题 React 在重新渲染父组件时如何重用子组件/保留子组件的 state? - How does React re-use child components / keep the state of child components when re-rendering the parent component? 父组件在父状态更改时不必要地重新渲染子级 - Parent component unnecessarily re-rendering child on parent state change React Redux-父状态发生变化,但子组件未重新呈现 - React redux - parent state changing, but child components not re-rendering 尽管 Parent 中的状态发生了变化,但子组件不会重新渲染 - Child Components not re-rendering despite a state-change in Parent 父组件多次重新渲染子组件ReactJS - Parent component re-rendering child components multiple times ReactJS 无需重新渲染父组件即可访问子组件数据 - Access child components data without re-rendering parent React子组件不会在父状态更改时重新呈现 - React child component not re-rendering on parent state change 反应子组件不会在更新的父状态上重新渲染 - React child component not re-rendering on updated parent state 如何在不重新渲染组件的情况下更改 useState 的状态,而只是重新渲染其组件 - How to change useState's state without re-rendering the component, but just its components 停止重新渲染父组件。 仅重新渲染子组件 - Stop Re-Rendering of Parent Components. Only Re-Render Child Component
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM