Guest User

Untitled

a guest
Nov 23rd, 2017
68
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.85 KB | None | 0 0
  1. const React = require("react");
  2.  
  3. // An item in the infinite scroll
  4. class ScrollItem extends React.Component {
  5. constructor(props) {
  6. super(props);
  7. this.state = {
  8. minHeight: props.minHeight
  9. }
  10. }
  11.  
  12. render() {
  13. return <div ref={node => this.node = node}
  14. data-infinite-scroll={this.props.index}
  15. style={{minHeight: this.state.minHeight}}>
  16. {this.props.show && this.props.render(Object.assign({index: this.props.index}, this.props.data))}
  17. </div>;
  18. }
  19.  
  20. componentWillReceiveProps(nextProps) {
  21. if(nextProps.show == false && this.props.show == true) {
  22. this.setState({minHeight: this.node.clientHeight})
  23. }
  24. }
  25.  
  26. componentDidMount() {
  27. this.props.observers.forEach(observer => observer && observer.observe(this.node));
  28. }
  29.  
  30. componentWillUnmount() {
  31. this.props.observers.forEach(observer => observer && observer.unobserve(this.node));
  32. }
  33. }
  34.  
  35. // When this becomes visible, we call loadMore()
  36. class ScrollLoadMore extends React.Component {
  37. render() {
  38. return <div ref={node => this.node = node} data-infinite-scroll="load-more"/>;
  39. }
  40.  
  41. componentDidMount() {
  42. this.props.observers.forEach(observer => observer && observer.observe(this.node));
  43. }
  44.  
  45. componentWillUnmount() {
  46. this.props.observers.forEach(observer => observer && observer.unobserve(this.node));
  47. }
  48. }
  49.  
  50. // Basic Infinite Scroll, toggles showing items
  51. class InfiniteScrollBase extends React.Component {
  52. constructor(props) {
  53. super(props);
  54. this.state = {
  55. visibleComponents: {0: true},
  56. itemCount: 1
  57. }
  58. if(global.IntersectionObserver) {
  59. this.loadObserver = new IntersectionObserver((x) => this.intersectionCallback(x), {
  60. rootMargin: props.loadMargin || "100px 0px"
  61. });
  62. }
  63. }
  64.  
  65. componentWillUnmount() {
  66. this.loadObserver && this.loadObserver.disconnect();
  67. }
  68.  
  69. intersectionCallback(entries) {
  70. var visibleComponents = this.state.visibleComponents;
  71. entries.forEach(entry => {
  72. const item = entry.target.getAttribute("data-infinite-scroll");
  73. if(item == 'load-more' && entry.isIntersecting) {
  74. this.props.loadNext();
  75. } else {
  76. visibleComponents = Object.assign({}, visibleComponents, {[item]: entry.isIntersecting});
  77. }
  78. })
  79. this.setState({visibleComponents: visibleComponents});
  80. }
  81.  
  82. render() {
  83. return <div>
  84. {this.props.items.map((data, index) =>
  85. <ScrollItem observers={this.props.observers.concat([this.loadObserver])}
  86. key={index}
  87. index={index}
  88. show={this.state.visibleComponents[index]}
  89. render={this.props.render}
  90. data={data}
  91. minHeight={this.props.minHeight || 50}/>)}
  92. <ScrollLoadMore observers={[this.loadObserver]} />
  93. </div>;
  94. }
  95. }
  96.  
  97. // Calls a callback when an item covers bottom 20% of the screen (to change URL)
  98. function withFocusObserver(Component) {
  99. return class WithFocusObserver extends React.Component {
  100. constructor(props) {
  101. super(props);
  102. if(global.IntersectionObserver) {
  103. this.focusObserver = new IntersectionObserver((x) => this.focusCallback(x), {
  104. rootMargin: `-${100 - props.focusCallbackAt}% 0px -${props.focusCallbackAt}%`
  105. })
  106. }
  107. }
  108.  
  109. componentWillUnmount() {
  110. this.focusObserver && this.focusObserver.disconnect();
  111. }
  112.  
  113. focusCallback(entries) {
  114. entries.forEach(entry => {
  115. const item = entry.target.getAttribute("data-infinite-scroll");
  116. if(entry.isIntersecting) {
  117. this.props.focusCallback(item)
  118. }
  119. });
  120. }
  121.  
  122. render() {
  123. return React.createElement(Component, Object.assign({}, this.props, {
  124. observers: (this.props.observers || []).concat([this.focusObserver])
  125. }))
  126. }
  127. }
  128. }
  129.  
  130. const InfiniteScroll = withFocusObserver(InfiniteScrollBase);
  131.  
  132. class TestComponent extends React.Component {
  133. constructor(props) {
  134. super(props);
  135. this.state = {
  136. loading: false,
  137. items: [{headline: "story-0"}]
  138. }
  139.  
  140. }
  141.  
  142. loadNext() {
  143. if(this.state.loading)
  144. return;
  145. this.setState({loading: true});
  146. setTimeout(() => this.setState({loading: false, items: this.state.items.concat([{headline: `random-${Math.random()}`},{headline: `random-${Math.random()}`},{headline: `random-${Math.random()}`},{headline: `random-${Math.random()}`},{headline: `random-${Math.random()}`}])}), 200)
  147. }
  148.  
  149. render() {
  150. return <InfiniteScroll render={(props) => <div className="scroll-component">{props.index} - {props.headline}</div>}
  151. items={this.state.items}
  152. minHeight={50}
  153. loadNext={() => this.loadNext()}
  154. loadMargin="200px 0px 100px"
  155. focusCallbackAt={20}
  156. focusCallback={(x) => console.log("Focussed Item", x)}/>
  157. }
  158. }
  159.  
  160. exports.TestComponent = TestComponent;
Add Comment
Please, Sign In to add comment