我继承了一个react / node / prismic应用程序,在该应用程序中我们需要更新prismic-reactjs程序包,这导致需要更新一些其他程序,总共,我们进行了更改:

棱镜反应式:0.2.0→1.1.0

反应:15.6.1→16.0.0

网络包:3.12.0→4.39.2

react-dom:15.6.1→16.0.0

react-router-dom:4.1.2→5.0.1

extract-text-webpack-plugin(已弃用)→mini-css-extract-plugin

然后由于启动本地服务器时的新错误而删除了“ withRouter()”的一种用法(但我在另一个分支中确认,仅进行该编辑不会产生以下症状)

上下文:我们有一个personMap,它显示一组人的图标,然后单击其中的一个以打开PersonMapStory模式,该模式显示该人的故事,然后链接到底部列表中的其他所有人。如果向下滚动并单击这些链接之一,则顶部的故事将被相应的人替换(用新人物的故事),下面列出的是其他所有人。在代码中,这些底部链接的按钮onClick行为设置为此新人员的setActivePerson()。

新错误:在这个新分支中,当我打开故事模式并简单地将鼠标悬停在页面上并再次返回时,我们将重复与onMouseEnter和onMouseLeave关联的setQueuedUpPerson和setNoQueuedUpPerson调用。 (在上一个/生产代码中不会发生)。这导致了下游问题,我正在尝试找出如何防止这种情况的发生。

进一步的信息:我已经看到了propagation issue的解决方案,该解决方案是通过适当的方法传递事件并调用stopPropagation,这似乎是相同的行为。有没有一种方法可以执行相同的操作,以使模态启动时停止监听悬停行为?

更新了PersonMap.js(来自第一个建议的答案):

import Modal from 'react-modal'
import PropTypes from 'prop-types'
import React from 'react'

import PersonMapPoint from './PersonMapPoint'
import PersonMapStory from './PersonMapStory'
import PersonMapCallout from './PersonMapCallout'
import PersonMapLocator from './PersonMapLocator'
import PersonMapBackground from './PersonMapBackground'

const CUSTOM_STYLES = {
    content: {
        top: 0,
        left: 0,
        right: 0,
        bottom: 0,
        backgroundColor: '#fff',
        zIndex: 10,
        border: 'none'
    }
}

class PersonMap extends React.Component {
    constructor(props) {
        super(props)

        this.setActivePerson = this.setActivePerson.bind(this)
        this.setNoActivePerson = this.setNoActivePerson.bind(this)
        this.setQueuedUpPerson = this.setQueuedUpPerson.bind(this)
        this.setNoQueuedUpPerson = this.setNoQueuedUpPerson.bind(this)
        this.checkBlurEvent = this.checkBlurEvent.bind(this)
        this.setIsDesktop = this.setIsDesktop.bind(this)
        this.checkHasBeenScrolledTo = this.checkHasBeenScrolledTo.bind(this)
        this.setTopRef = this.setTopRef.bind(this)
        this.handleKeyPress = this.handleKeyPress.bind(this)

        this.state = {
            activePerson: null,
            queuedUpPerson: null,
            scrollPos: 0,
            isDesktop: false,
            hasBeenScrolledTo: false,
            lastQueuedPerson: null
        }
    }

    componentDidMount() {
        this.setIsDesktop()
        this.checkHasBeenScrolledTo()
        window.addEventListener('resize', this.setIsDesktop)
        window.addEventListener('scroll', this.checkHasBeenScrolledTo)
    }

    componentWillUnmount() {
        window.removeEventListener('resize', this.setIsDesktop)
        window.removeEventListener('scroll', this.checkHasBeenScrolledTo)
    }

    setTopRef(element) {
        this.topRef = element
    }

    setActivePerson(personName) {
        this.setState({
            activePerson: personName,
            scrollPos: window.scrollY
        })
    }

    setNoActivePerson() {
        this.setState({
            queuedUpPerson: this.state.activePerson,
            activePerson: null
        }, () => {
            setTimeout(() => {
                window.scrollTo(0, this.state.scrollPos)
            }, 50)
        })
    }

    setQueuedUpPerson(e, personName) {
        this.setState({
            queuedUpPerson: personName,
            lastQueuedPerson: personName
        })
        e.stopPropagation()
    }

    setNoQueuedUpPerson(e) {
        this.setState({
            queuedUpPerson: null
        })
        e.stopPropagation()
    }

    handleKeyPress(e, name) {
        if (e.key !== ' ' && e.key !== 'Enter') {
            return
        }
        this.setActivePerson(name)
    }

    checkBlurEvent(e) {
        if (Array.from(e.currentTarget.childNodes[0].childNodes).includes(e.relatedTarget)) {
            return
        }
        this.setNoQueuedUpPerson(e)
    }

    render() {
        return (
            <section className="slice-area person-map CONSTRAIN">
                <div className="person-map-headers">
                    <div className="person-map-headers-inner">
                        <h1 className="person-map-title">
                            {this.props.title}
                        </h1>
                        <p className="person-map-disclaimer">
                            {this.props.disclaimer}
                        </p>
                    </div>
                </div>
                {
                    !this.state.isDesktop &&
                    <div className="person-map-graphic" ref={this.setTopRef}>
                        {
                            this.props.personStories.map(person => (
                                <PersonMapLocator
                                    x={person.x}
                                    y={person.y}
                                    key={person.name}
                                >
                                    <PersonMapPoint name={person.name}/>
                                </PersonMapLocator>
                            ))
                        }
                        <PersonMapBackground isVisible={this.state.hasBeenScrolledTo} />
                    </div>
                }
                <div
                    className={`person-map-list-wrap${ this.state.isDesktop ? ' --desktop' : '' }`}
                    ref={this.state.isDesktop && this.setTopRef}
                >
                    { this.state.isDesktop &&
                        <PersonMapBackground isVisible={this.state.hasBeenScrolledTo}/>
                    }
                    <ul className="person-map-list">
                        {
                            this.props.personStories.map((person) => {
                                const thisPersonIsQueued = this.state.queuedUpPerson === person.name
                                const thisPersonIsActive = this.state.activePerson === person.name
                                const thisPersonWasLastQueued = this.state.lastQueuedPerson === person.name

                                return (
                                    <li
                                        key={person.name} className={`person-map-list-item${thisPersonWasLastQueued ? ' --active' : ''}`}
                                        onMouseEnter={this.state.isDesktop ? (e) => this.setQueuedUpPerson(e, person.name) : null}
                                        onMouseLeave={this.state.isDesktop ? this.setNoQueuedUpPerson : null}
                                        onFocus={this.state.isDesktop ? (e) => this.setQueuedUpPerson(e, person.name) : null}
                                        onBlur={this.state.isDesktop ? this.checkBlurEvent : null}
                                        onClick={thisPersonIsQueued || !this.state.isDesktop ? () => this.setActivePerson(person.name) : null}
                                        onKeyPress={(e) => this.handleKeyPress(e, person.name)}
                                    >
                                        {
                                            this.state.isDesktop ?
                                                <PersonMapLocator
                                                    x={person.x}
                                                    y={person.y}
                                                >
                                                    <PersonMapPoint
                                                        name={person.name}
                                                        isInteractive
                                                        isActive={thisPersonIsQueued}
                                                        imageUrl={person.photo_url}
                                                    />
                                                    <PersonMapCallout
                                                        name={person.name}
                                                        photo={person.photo_url}
                                                        isOpen={thisPersonIsQueued}
                                                        isDesktop
                                                    />
                                                </PersonMapLocator> :
                                                <PersonMapCallout
                                                    name={person.name}
                                                    photo={person.photo_url}
                                                />
                                        }
                                        <Modal
                                            isOpen={thisPersonIsActive}
                                            onRequestClose={this.setNoActivePerson}
                                            style={CUSTOM_STYLES}
                                        >
                                            <PersonMapStory
                                                name={person.name}
                                                photo={person.photo_url}
                                                story={person.story}
                                                setNoActivePerson={this.setNoActivePerson}
                                                setActivePerson={this.setActivePerson}
                                                isActive={thisPersonIsActive}
                                                otherPersons={this.props.personStories.filter((item) => item.name !== person.name).map((item) => ({ name: item.name, photo: item.photo_url }))}
                                                isDesktop={this.state.isDesktop}
                                            />
                                        </Modal>
                                    </li>
                                )
                            })
                        }
                    </ul>
                </div>
            </section>
        )
    }
}

PersonMap.propTypes = {
    title: PropTypes.string,
    disclaimer: PropTypes.string,
    personStories: PropTypes.arrayOf(PropTypes.shape({
        name: PropTypes.string,
        photo_url: PropTypes.string,
        x: PropTypes.number,
        y: PropTypes.number,
        story: PropTypes.shape({
            title: PropTypes.string,
            link: PropTypes.string,
            content: PropTypes.arrayOf(PropTypes.shape({
                question: PropTypes.string,
                answer: PropTypes.string
            }))
        })
    }))
}

export default PersonMap


原始PersonMap.js:

import Modal from 'react-modal'
import PropTypes from 'prop-types'
import React from 'react'

import PersonMapPoint from './PersonMapPoint'
import PersonMapStory from './PersonMapStory'
import PersonMapCallout from './PersonMapCallout'
import PersonMapLocator from './PersonMapLocator'
import PersonMapBackground from './PersonMapBackground'

const CUSTOM_STYLES = {
    content: {
        top: 0,
        left: 0,
        right: 0,
        bottom: 0,
        backgroundColor: '#fff',
        zIndex: 10,
        border: 'none'
    }
}

class PersonMap extends React.Component {
    constructor(props) {
        super(props)

        this.setActivePerson = this.setActivePerson.bind(this)
        this.setNoActivePerson = this.setNoActivePerson.bind(this)
        this.setQueuedUpPerson = this.setQueuedUpPerson.bind(this)
        this.setNoQueuedUpPerson = this.setNoQueuedUpPerson.bind(this)
        this.checkBlurEvent = this.checkBlurEvent.bind(this)
        this.setIsDesktop = this.setIsDesktop.bind(this)
        this.checkHasBeenScrolledTo = this.checkHasBeenScrolledTo.bind(this)
        this.setTopRef = this.setTopRef.bind(this)
        this.handleKeyPress = this.handleKeyPress.bind(this)

        this.state = {
            activePerson: null,
            queuedUpPerson: null,
            scrollPos: 0,
            isDesktop: false,
            hasBeenScrolledTo: false,
            lastQueuedPerson: null
        }
    }

    componentDidMount() {
        this.setIsDesktop()
        this.checkHasBeenScrolledTo()
        window.addEventListener('resize', this.setIsDesktop)
        window.addEventListener('scroll', this.checkHasBeenScrolledTo)
    }

    componentWillUnmount() {
        window.removeEventListener('resize', this.setIsDesktop)
        window.removeEventListener('scroll', this.checkHasBeenScrolledTo)
    }

    setTopRef(element) {
        this.topRef = element
    }

    setActivePerson(personName) {
        this.setState({
            activePerson: personName,
            scrollPos: window.scrollY
        })
        event.stopPropagation()
    }

    setNoActivePerson() {
        this.setState({
            queuedUpPerson: this.state.activePerson,
            activePerson: null
        }, () => {
            setTimeout(() => {
                window.scrollTo(0, this.state.scrollPos)
            }, 50)
        })
    }

    setQueuedUpPerson(personName) {
        this.setState({
            queuedUpPerson: personName,
            lastQueuedPerson: personName
        })
    }

    setNoQueuedUpPerson() {
        this.setState({
            queuedUpPerson: null
        })
        event.stopPropagation()
    }

    handleKeyPress(e, name) {
        if (e.key !== ' ' && e.key !== 'Enter') {
            return
        }
        this.setActivePerson(name)
    }

    checkBlurEvent(e) {
        if (Array.from(e.currentTarget.childNodes[0].childNodes).includes(e.relatedTarget)) {
            return
        }
        this.setNoQueuedUpPerson()
    }

    render() {
        return (
            <section className="slice-area person-map CONSTRAIN">
                <div className="person-map-headers">
                    <div className="person-map-headers-inner">
                        <h1 className="person-map-title">
                            {this.props.title}
                        </h1>
                        <p className="person-map-disclaimer">
                            {this.props.disclaimer}
                        </p>
                    </div>
                </div>
                <div
                    className={`person-map-list-wrap${ this.state.isDesktop ? ' --desktop' : '' }`}
                    ref={this.state.isDesktop && this.setTopRef}
                >
                    { this.state.isDesktop &&
                        <PersonMapBackground isVisible={this.state.hasBeenScrolledTo}/>
                    }
                    <ul className="person-map-list">
                        {
                            this.props.personStories.map((person) => {
                                const thisPersonIsQueued = this.state.queuedUpPerson === person.name
                                const thisPersonIsActive = this.state.activePerson === person.name
                                const thisPersonWasLastQueued = this.state.lastQueuedPerson === person.name

                                return (
                                    <li
                                        key={person.name} className={`person-map-list-item${thisPersonWasLastQueued ? ' --active' : ''}`}
                                        onMouseEnter={this.state.isDesktop ? () => this.setQueuedUpPerson(person.name) : null}
                                        onMouseLeave={this.state.isDesktop ? this.setNoQueuedUpPerson : null}
                                        onFocus={this.state.isDesktop ? () => this.setQueuedUpPerson(person.name) : null}
                                        onBlur={this.state.isDesktop ? this.checkBlurEvent : null}
                                        onClick={thisPersonIsQueued || !this.state.isDesktop ? () => this.setActivePerson(person.name) : null}
                                        onKeyPress={(e) => this.handleKeyPress(e, person.name)}
                                    >
                                        {
                                                <PersonMapLocator
                                                    x={person.x}
                                                    y={person.y}
                                                >
                                        }
                                        <Modal
                                            isOpen={thisPersonIsActive}
                                            onRequestClose={this.setNoActivePerson}
                                            style={CUSTOM_STYLES}
                                        >
                                            <PersonMapStory
                                                name={person.name}
                                                photo={person.photo_url}
                                                story={person.story}
                                                setNoActivePerson={this.setNoActivePerson}
                                                setActivePerson={this.setActivePerson}
                                                isActive={thisPersonIsActive}
                                                otherPersons={this.props.personStories.filter((item) => item.name !== person.name).map((item) => ({ name: item.name, photo: item.photo_url }))}
                                                isDesktop={this.state.isDesktop}
                                            />
                                        </Modal>
                                    </li>
                                )
                            })
                        }
                    </ul>
                </div>
            </section>
        )
    }
}

PersonMap.propTypes = {
    title: PropTypes.string,
    disclaimer: PropTypes.string,
    personStories: PropTypes.arrayOf(PropTypes.shape({
        name: PropTypes.string,
        photo_url: PropTypes.string,
        x: PropTypes.number,
        y: PropTypes.number,
        story: PropTypes.shape({
            title: PropTypes.string,
            link: PropTypes.string,
            content: PropTypes.arrayOf(PropTypes.shape({
                question: PropTypes.string,
                answer: PropTypes.string
            }))
        })
    }))
}
export default PersonMap


PersonMapStory.js:

import PropTypes from 'prop-types'
import React from 'react'

import PersonMapPerson from './PersonMapPerson'


class PersonMapStory extends React.Component {
    constructor(props) {
        console.log("PersonMapStory constructor")
        super(props)

        this.deactivateThisPerson = this.deactivateThisPerson.bind(this)
        this.check = 0
    }

    deactivateThisPerson(backPressed = false) {
        if (!backPressed) {
            history.back()
        }
        console.log("Set no active person ")
        this.props.setNoActivePerson()
    }

    setActivePerson(name) {
        this.props.setActivePerson(name)
        event.stopPropagation()
    }


    componentDidMount() {
        const loc = window.location.pathname.substr(1)
        this.setState({ location: loc })
        const openState = { modalOpen: true }
        history.pushState(openState, 'signup-open', loc)
      }

    render() {
        return (
            <div className={`person-map-story${this.props.isActive ? ' --active' : ''}${this.props.isDesktop ? ' --desktop' : ''}`}>
                <h2 className="person-map-story-title">
                    { this.props.story.title }
                </h2>
                <button className="person-map-story-close-button" onClick={() => {this.deactivateThisPerson(false)}}>
                    <span className="person-map-story-close-button-text">
                        Close Story
                    </span>
                </button>
                <div className="person-map-story-body">
                    <span className="person-map-story-person-wrap">
                        <PersonMapPerson
                            photo={this.props.photo}
                            name={this.props.name}
                        />
                    </span>
                    {
                        this.props.story.content.map((section) => {
                            if (section) {
                                return (
                                    <div key={section.question}>
                                        <h3 className="person-map-story-question">{section.question}</h3>
                                        <p className="person-map-story-answer">
                                            {section.answer}
                                        </p>
                                    </div>
                                )
                            }
                        })
                    }
                    {
                        this.props.story.link &&
                        <a  href={this.props.story.link}
                            target="_blank"
                            className="person-map-story-more-link header-and-text-link"
                        >  Read More Stories
                        </a>
                    }

                    <ul className="person-map-story-other-list">
                        {
                            this.props.otherPersons.map((person) => (
                                <li
                                    key={person.name}
                                    className="person-map-story-other-list-item"
                                >
                                    <button className="person-map-story-other-button" onClick={() => this.setActivePerson(person.name)}>
                                        <PersonMapPerson
                                            name={person.name}
                                            photo={person.photo}
                                            ctaText="View their story"
                                        />
                                    </button>
                                </li>
                            ))
                        }
                    </ul>
                </div>
            </div>
        )
    }
}

PersonMapStory.propTypes = {
    name: PropTypes.string,
    photo: PropTypes.string,
    story: PropTypes.shape({
        title: PropTypes.string,
        link: PropTypes.string,
        content: PropTypes.arrayOf(PropTypes.shape({
            question: PropTypes.string,
            answer: PropTypes.string
        }))
    }),
    setNoActivePerson: PropTypes.func,
    setActivePerson: PropTypes.func,
    isActive: PropTypes.bool,
    otherPersons: PropTypes.arrayOf(PropTypes.shape({
        name: PropTypes.string,
        photo: PropTypes.string
    })),
    isDesktop: PropTypes.bool
}

export default PersonMapStory

最佳答案

更新(如下所示不起作用):

您是否可以取消activePerson中是否存在state模态,这是否意味着您不希望setQueuedUpPersonsetNoQueuedUpPerson调用?可以这样更改它们:

setQueuedUpPerson(e, personName) {
    if(!this.state.activePerson) {
      this.setState({
          queuedUpPerson: personName,
          lastQueuedPerson: personName
      })
    }

    e.stopPropagation()
}

setNoQueuedUpPerson(e) {
    if(!this.state.activePerson) {
      this.setState({
          queuedUpPerson: null
      })
    }
    e.stopPropagation()
}


或者,如果存在onMouseEnter,则将onMouseLeaveactivePerson事件设置为null?



你应该能够改变

onMouseEnter={this.state.isDesktop ? () => this.setQueuedUpPerson(person.name) : null}




onMouseEnter={this.state.isDesktop ? (e) => this.setQueuedUpPerson(e,person.name) : null}


然后像上一个问题一样访问事件以停止传播:

setQueuedUpPerson(event, personName) {
    this.setState({
        queuedUpPerson: personName,
        lastQueuedPerson: personName
    })
    event.stopPropagation()
}


使用onMouseLeave时,您只需将event参数添加到您的函数中,因为它已经公开,因为您是直接传递函数引用,而不是像onMouseEnter这样从匿名函数中调用它:

setNoQueuedUpPerson(event) {
    this.setState({
        queuedUpPerson: null
    })
    event.stopPropagation()
}

10-06 01:11