Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React JS Context API - Window Scroll Events

I've looked at what I believe may be two outdated answers given React 16's Context API.

They are:

React.js best practice regarding listening to window events from components

And:

How to implement service(concept in AngularJS) -like component in React

I'm fairly new to React, so I was wondering, given the Context API, is the correct way to do an Angular.js type of service in React (so I don't have window.addEventListener("scroll") on every component that is listening to the scroll event, to leverage the Context API (create the event listener there?). Just wondering if I'm on the right track here...

It talks about being able to pass down props, and also about nested components being able to change the state, would it be wrong to have a wrapper component collecting the scroll position, updating the Context (scroll position), and passing that down to the needed elements? Is there a recommended way to do this and are multiple window.addEventListener("scroll") even a problem?

I was having trouble understanding how to update the context from a nested component once it was created - in the docs here: https://reactjs.org/docs/context.html#updating-context-from-a-nested-component

So I'm not sure about updating context from a top-level/parent element and passing it down to the interior components.

like image 613
Summer Developer Avatar asked Dec 18 '22 22:12

Summer Developer


1 Answers

You can use the context API to create a Provider with a HoC. Whenever the window size changes, the provider notify's the consumer by updating the width/height, and the consumer in the HoC, rerenders the components.

Example:

const getDimensions = () => ({
  width: window.innerWidth,
  height: window.innerHeight
});

const ResizeContext = React.createContext(getDimensions());

class ResizeProvider extends React.PureComponent {
  state = getDimensions();
  
  // you might want to debounce or throttle the event listener
  eventListener = () => this.setState(getDimensions());

  componentDidMount() {
    window.addEventListener('resize', this.eventListener);
  }
  
  componentWillUnmount() {
    window.removeEventListener('resize', this.eventListener);
  }
  
  render() {
    return (
      <ResizeContext.Provider value={this.state}>
      {
        this.props.children
      }
      </ResizeContext.Provider>
    );
  }
}

const withResize = (Component) => (props) => (
  <ResizeContext.Consumer>
  {({ width, height }) => (
    <Component {...props} width={width} height={height} />
  )}
  </ResizeContext.Consumer>
);
  
const ShowSize = withResize(({ width, height }) => (
  <div>
    <div>Width: {width}</div>
    <div>Height: {height}</div>
  </div>
));

const Demo = () => (
  <ResizeProvider>
    <ShowSize />
  </ResizeProvider>
);

ReactDOM.render(
  <Demo />,
  demo
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="demo"></div>
like image 88
Ori Drori Avatar answered Dec 28 '22 11:12

Ori Drori