Переключение состояния и класса HTML при прокрутке элемента [React, Gatsby] - PullRequest
0 голосов
/ 27 января 2020

Используя Gatsby, у меня есть пользовательский компонент InvertedSection, который меняет класс элемента HTML при прокрутке раздела, позволяя мне изменить стиль заголовка. То есть, когда верхняя часть элемента с перевернутой секцией достигает верхней части окна, и пока нижняя часть элемента с перевернутой секцией не достигает верхней части окна, заголовок является прозрачным. Я выполняю sh, используя состояние Redux.

В моем компоненте invertedSection.js я переключаю состояние локально - чтобы ограничить вызовы Redux только при локальном изменении состояния - а также используя Redux createStore.js. Затем в layout.js я использую состояние Redux для установки HTML className с использованием React шлем .

Моя проблема двоякая:

  1. при навигации со страницы, использующей компонент InvertedSection, до страницы, которая не использует этот компонент, состояние Redux invertedHeader устанавливается равным true и
  2. , если у меня несколько разделов InvertedSection на одном страница, изменение состояния работает только для первого раздела, а не для любых последующих перевернутых разделов.

I думаю проблема с (1) выше заключается в том, что страница прокручивается вверх где находится InvertedSection, прежде чем перейти на новую страницу, таким образом, invertedHeader будет true при загрузке новой страницы. Но я не могу найти, как заставить редукс сбрасывать это состояние при каждом изменении маршрута.

Мысли? Все работает, если я перехожу на / со страниц, которые обе содержат InvertedSection, поэтому, возможно, мне нужно вызывать обработчик прокрутки на каждой странице? ИЛИ хотя бы вызвать проверку положения прокрутки и изменение состояния? Redux для меня немного новый, так что это может немного сбивать с толку.

Спасибо!

# Component
# /components/invertedSection.js

import React, { useState, useEffect } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'

const InvertedSection = ({ invertHeader, revertHeader, className, children }) => {
  let targetSection = React.createRef()

  const [isViz, setIsViz] = useState(false)

  useEffect(() => {
    handleScroll()
    window.addEventListener('scroll', handleScroll, true)
    return () => {
      window.removeEventListener('scroll', handleScroll, true)
    }
  })

  const handleScroll = () => {
    if (targetSection.current) {
      const rect = targetSection.current.getBoundingClientRect()
      if (rect && rect.top <= 0 && rect.bottom >= 0) {
        if (!isViz) {
          setIsViz(true)
          invertHeader()
          console.log('header invert')
        }
      } else {
        if (isViz) {
          setIsViz(false)
          revertHeader()
          console.log('header revert')
        }
      }
    }
  }

  return (
    <section ref={targetSection} className={className}>
      {children}
    </section>
  )
}

InvertedSection.propTypes = {
  invertHeader: PropTypes.func.isRequired,
  revertHeader: PropTypes.func.isRequired,
}

const mapStateToProps = ({ invertedHeader }) => {
  return { invertedHeader }
}

const mapDispatchToProps = dispatch => {
  return {
    invertHeader: () => dispatch({ type: `INVERTHEADER` }),
    revertHeader: () => dispatch({ type: `REVERTHEADER` }),
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(InvertedSection)
# Redux
# /state/createStore.js

import { createStore as reduxCreateStore } from 'redux'

const reducer = (state, action) => {
  switch (action.type){
    case `INVERTHEADER`:
      return Object.assign({}, state, {
        invertedHeader: true,
      })
    case `REVERTHEADER`:
      return Object.assign({}, state, {
        invertedHeader: false,
      })
    default:
      break
  }
  return state
}

const initialState = {
  invertedHeader: false,
}

const createStore = () => reduxCreateStore(reducer, initialState)

export default createStore
# Layout
# /components/layout.js

import React, { useEffect } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { useStaticQuery, graphql } from 'gatsby'
import { ThemeProvider } from 'styled-components'

import theme from '../styles/theme'
import Helmet from 'react-helmet'
import GlobalStyle from '../styles/global'
import SiteHeader from './siteHeader/siteHeader'
import SiteFooter from './sitefooter/siteFooter'

const Layout = ({ children, invertedHeader }) => {
  const data = useStaticQuery(graphql`
    query {
      site {
        ...siteMeta
      }
    }
  `)

  return (
    <ThemeProvider theme={theme}>
      <Helmet>
        <html className={`${invertedHeader ? 'inverted-header' : ''}`} />
      </Helmet>
      <GlobalStyle />
      <SiteHeader
        siteTitle={data.site.siteMetadata.title}
      />
      {children}
      <SiteFooter />
    </ThemeProvider>
  )
}

Layout.propTypes = {
  children: PropTypes.node.isRequired,
  invertedHeader: PropTypes.bool.isRequired,
}

const mapStateToProps = ({ showNav, invertedHeader }) => {
  return { showNav, invertedHeader }
}

export default connect(mapStateToProps)(Layout)
# Index
# /pages/index.js

import React from 'react'
import Layout from '../components/layout'
import InvertedSection from '../components/section'

export default ({ data }) => {
  return (
    <Layout>
      <InvertedSection>
        This section uses an inverted header state
      </InvertedSection>
      <section>
        This section uses normal header state
      </section>
    </Layout>
  )
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...