Advertisement
Guest User

Untitled

a guest
Aug 22nd, 2019
469
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.72 KB | None | 0 0
  1. import React, { useState, useEffect } from 'react'
  2. import { useSpring, animated, interpolate } from 'react-spring'
  3. import { useDrag } from 'react-use-gesture'
  4.  
  5. // let's handle gestures within our pager component
  6.  
  7. const PAGE_SIZE = 375
  8. // arbitrary value that will determine if we should transition after dragging
  9. const DRAG_THRESHOLD = Math.floor(PAGE_SIZE * 0.3)
  10.  
  11. function Pager({ children, activeIndex, onChange }) {
  12. const offset = activeIndex * 100 * -1
  13.  
  14. // dragX will represent the current drag value to animate
  15. const [{ translateX, dragX }, set] = useSpring(() => ({
  16. translateX: offset,
  17. dragX: 0,
  18. }))
  19.  
  20. // this might look a bit strange but it's part of the api for useDrag
  21. // bind() is a function we'll add to our container div that gives us a bunch of gesture state data
  22. // think of this as an event listener for gestures
  23.  
  24. const bind = useDrag(({ delta, last, vxvy }) => {
  25. // this is the drag value
  26. const [x] = delta
  27.  
  28. // the velocity of the drag -- important to track to prevent jank after user releases
  29. const [vx] = vxvy
  30.  
  31. // we want the value to immediate update w/ a user drag event, not spring to the value
  32. set({ dragX: x, immediate: true })
  33.  
  34. // last is true when the user releases from dragging
  35. if (last) {
  36. // user has dragged beyond our threshold to transition (either left or right)
  37. const shouldTransition = Math.abs(x) >= DRAG_THRESHOLD
  38.  
  39. if (!shouldTransition) {
  40. // restore to initial position when user started dragging:
  41. set({ dragX: 0, immediate: false })
  42. } else {
  43. // determine the next position based on the drag value (left or right)
  44. let nextPosition
  45.  
  46. if (x > DRAG_THRESHOLD) {
  47. // transition to previous page
  48. nextPosition = offset + 100
  49.  
  50. // update our controller component w/ the previous index
  51. onChange(activeIndex - 1)
  52. }
  53.  
  54. if (x < DRAG_THRESHOLD) {
  55. // transition to next page
  56. nextPosition = offset - 100
  57.  
  58. // update our controller component w/ the next index
  59. onChange(activeIndex + 1)
  60. }
  61.  
  62. // start spring transition to next position
  63. // we want to spring the drag value back to 0 as we translate to the next position
  64. set({
  65. dragX: 0,
  66. translateX: nextPosition,
  67. immediate: false,
  68. config: {
  69. velocity: vx,
  70. },
  71. })
  72. }
  73. }
  74. })
  75.  
  76. useEffect(() => {
  77. set({ translateX: offset })
  78. }, [offset, set])
  79.  
  80. // attach the bind() function to our container div to listen for gesture events
  81. // we will now include our drag values in the interpolate() function below
  82. return (
  83. <animated.div
  84. {...bind()}
  85. style={{
  86. border: 'thin solid blue',
  87. position: 'relative',
  88. height: '100%',
  89. width: '100%',
  90. transform: interpolate(
  91. [translateX, dragX],
  92. (translateX, dragX) => `translateX(calc(${translateX}% + ${dragX}px))`,
  93. ),
  94. }}>
  95. {React.Children.map(children, (element, index) => {
  96. return (
  97. <div
  98. style={{
  99. ...absoluteFill,
  100. transform: `translateX(${index * 100}%)`,
  101. }}>
  102. {element}
  103. </div>
  104. )
  105. })}
  106. </animated.div>
  107. )
  108. }
  109.  
  110. const absoluteFill = {
  111. position: 'absolute',
  112. left: 0,
  113. right: 0,
  114. bottom: 0,
  115. top: 0,
  116. }
  117.  
  118.  
  119. // this will represent a consumer component or any part of your application
  120. function App() {
  121. // all we need to pass are children and an activeIndex prop to our pager component
  122. const [activeIndex, setActiveIndex] = useState(3)
  123.  
  124. function handleChange(index) {
  125. setActiveIndex(index)
  126. }
  127.  
  128. const children = Array.from({ length: 10 }).map((c, i) => (
  129. <h1 key={i} style={{ textAlign: 'center' }}>
  130. Index {i}
  131. </h1>
  132. ))
  133.  
  134. return (
  135. <div style={{ overflow: 'hidden' }}>
  136. <div
  137. style={{
  138. width: PAGE_SIZE,
  139. height: PAGE_SIZE,
  140. display: 'flex',
  141. margin: 'auto',
  142. padding: '5px',
  143. border: 'thin solid red',
  144. }}>
  145. <Pager activeIndex={activeIndex} onChange={handleChange}>{children}</Pager>
  146. </div>
  147.  
  148. <div
  149. style={{
  150. display: 'flex',
  151. flexDirection: 'column',
  152. alignItems: 'center',
  153. justifyContent: 'space-around',
  154. }}>
  155. <strong style={{ margin: '5px 0' }}>activeIndex: {activeIndex}</strong>
  156. <button
  157. style={{ margin: '5px 0' }}
  158. onClick={() => setActiveIndex(activeIndex + 1)}>
  159. Increment
  160. </button>
  161. <button
  162. style={{ margin: '5px 0' }}
  163. onClick={() => setActiveIndex(activeIndex - 1)}>
  164. Decrement
  165. </button>
  166. </div>
  167. </div>
  168. )
  169. }
  170.  
  171. export default App
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement