React JS Context API-窗口滚动事件

时间:2018-07-20 20:01:34

标签: javascript reactjs

我已经查看了我认为对于React 16的Context API可能是两个过时的答案。

它们是:

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

并且:

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

我对React还是很陌生,所以我想知道,考虑到Context API,这是在React中进行Angular.js类型服务的正确方法(所以我没有{{1} }在正在侦听滚动事件的每个组件上利用Context API(在此处创建事件侦听器?),只是想知道我是否在正确的轨道上……

它讨论了能够传递道具,还谈到了嵌套组件能够改变状态,让包装器组件收集滚动位置,更新Context(滚动位置)并传递它是错误的。到所需的要素?有没有推荐的方法来做到这一点,并且多个window.addEventListener("scroll")甚至是一个问题吗?

创建嵌套组件时,我很难理解如何从其更新上下文-在此处的文档中:https://reactjs.org/docs/context.html#updating-context-from-a-nested-component

因此,我不确定要从顶级/父元素更新上下文并将其传递给内部组件。

1 个答案:

答案 0 :(得分:9)

您可以使用context API创建带有HoC的提供者。每当窗口大小更改时,提供者都会通过更新宽度/高度来通知消费者,而HoC中的消费者会重新提供组件。

示例:

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>