React Context и Provider для обработки событий прокрутки и видимости области просмотра - PullRequest
0 голосов
/ 05 мая 2020

Я столкнулся с препятствием при составлении описанного ниже процесса. Я пытаюсь создать контекст, который будет глобально предоставлять свойства окна компонентам, чтобы компоненты могли реагировать на изменения окна (прокрутка, изменение размера и т. Д. c).

Я делаю это для того, чтобы чем каждый компонент, выполняющий свой собственный набор прослушивателей событий. Мне нужно запустить только один набор и передать результаты вниз.

Пока что контекст добавляет слушателей прокрутки и изменения размера, регулирует их и делает значения доступными для оболочки поставщика. Все работает нормально, и значения доступны в обернутом компоненте.

//WindowContext.js

import React, { Component, createContext } from "react"
import throttle from "lodash.throttle"

export const WindowContext = createContext()

class WindowContextProvider extends Component {
  constructor(props) {
    super(props)
    this.state = {
      windowScrollY: null,
      windowInnerHeight: null,
    }
    this.throttledFunction = throttle(this.updateState, 500)
  }

  componentDidMount() {
    window.addEventListener("scroll", this.throttledFunction, false)
    window.addEventListener("resize", this.throttledFunction, false)
  }
  componentWillUnmount() {
    window.removeEventListener("scroll", this.throttledFunction, false)
    window.removeEventListener("resize", this.throttledFunction, false)
  }

  updateState = () => {
    this.setState({
      windowScrollY: window.scrollY,
      windowInnerHeight: window.innerHeight,
    })
  }

  render() {
    return (
      <WindowContext.Provider value={{ ...this.state }}>
        {this.props.children}
      </WindowContext.Provider>
    )
  }
}

export default WindowContextProvider


Проблема

В SomeComponent.js ниже вы можете увидеть, что это это то, что я пытаюсь сделать. У него две фундаментальные проблемы. Я не могу (не должен) устанавливать состояние в рендере, поэтому я не уверен, как я могу установить isActive в состоянии в значение true (чтобы какой-то тернарный оператор мог его использовать). И координаты элемента, которые я собираю в componentDidMount, - это stati c, что означает, что я не могу сопоставить их с прокруткой или внутренней высотой, чтобы определить, отображается ли элемент.

//SomeComponent.js

import React from "react"
import ReactDOM from "react-dom"

import { WindowContext } from "../contexts/WindowContext"

class DevTools extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      isActive: false, //want to set isActive:true if 
      element: null,
    }
  }
  componentDidMount = () => {
    this.setState({
      element: ReactDOM.findDOMNode(this).getBoundingClientRect(),
    })
  }

  render() {
    return (
      <WindowContext.Consumer>
        {context => {
          //THE CRUX OF THE PROBLEM
          const { windowScrollY, windowInnerHeight } = context
          console.log(windowScrollY) //tracked
          console.log(windowInnerHeight) //tracked
          console.log(this.state.element) //not tracked
          //this.state.element is currently static as it is simply set on mount, needs to be tracked
          //adding an event listener would defeat the point of creating the context

          //Below not an option, cannot set state within render, not sure how else to manage toggling when the element is visible
          handleWindowChange = () => { 
            if (this.state.element.top + 100 < windowInnerHeight && this.state.element.bottom >= 0) {
              this.setState({
                isActive: true,
              })
            }
          }
          return (
          //some div with a ternary operator

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

...