0

Question: I need to transform React Swipe this file to RN equivalent and it should respect the condition it should load only 3 articles at a time and display only one item
I am migrating a project from React + Cordova Project to Pure React Native. I have Swipe Functionality between bunch for i.e., let say 64 article. It will load first two articles when user swipes forward it will load next article and it will not load all the articles at a time.

interface IProps {
  slideRange?: number
  onChangeIndex?: (index: number) => void
  onTransitionEnd?: (index: number) => void
  axis?: 'x' | 'x-reverse' | 'y' | 'y-reverse'
  hysteresis?: number
  index?: number
  threshold?: number
  resistance?: boolean
  slides?: IGeneralArticle[]
  articleSource?: string
}

interface IState {
  indexLatest: number
  isDragging: boolean
  displaySameSlide: boolean
  isShowingSwipeAnimation: boolean
}

// We can only have one node at the time claiming ownership for handling the swipe.
// Otherwise, the UX would be confusing.
// That's why we use a singleton here.
const UNCERTAINTY_THRESHOLD = 3
const RESISTANCE_COEF = 0.6
const axisProperties = {
  rotationMatrix: {
    x: {
      x: [1, 0],
      y: [0, 1],
    },
    'x-reverse': {
      x: [-1, 0],
      y: [0, 1],
    },
    y: {
      x: [0, 1],
      y: [1, 0],
    },
    'y-reverse': {
      x: [0, -1],
      y: [1, 0],
    },
  },
}

// We are using a 2x2 rotation matrix.
const applyRotationMatrix = (
  touch: { pageX: number; pageY: number },
  axis: 'x' | 'x-reverse' | 'y' | 'y-reverse'
): { pageX: number; pageY: number } => {
  const rotationMatrix = axisProperties.rotationMatrix[axis]
  return {
    pageX: rotationMatrix.x[0] * touch.pageX + rotationMatrix.x[1] * touch.pageY,
    pageY: rotationMatrix.y[0] * touch.pageX + rotationMatrix.y[1] * touch.pageY,
  }
}

export class ReactSwipe extends React.PureComponent<IProps, IState> {
  public static defaultProps: IProps = {
    axis: 'x',
    hysteresis: 0.6,
    index: 0,
    threshold: 5,
    resistance: false,
  }

  private wrapperNode: HTMLDivElement
  private containerNode: HTMLDivElement
  private viewLength = 0
  private startX = 0
  private lastX = 0
  private vx = 0
  private startY = 0
  private isSwiping: boolean = undefined
  private started = false
  private startIndex = 0
  private indexCurrent: number = null
  private tutorialStorageKey = 'ReactSwipeAnimationShown'

  private handlerSwipeStart: EventListenerOrEventListenerObject = this.handleSwipeStart.bind(this)
  private handlerSwipeEnd: EventListenerOrEventListenerObject = this.handleSwipeEnd.bind(this)
  private handlerSwipeMove: EventListenerOrEventListenerObject = this.handleSwipeMove.bind(this)
  private handlerTransitionEnd: EventListenerOrEventListenerObject = this.handleTransitionEnd.bind(this)

  constructor(props: IProps) {
    super(props)
    this.state = {
      indexLatest: props.index,
      // Set to true as soon as the component is swiping.
      // It's the state counter part of this.isSwiping.
      isDragging: false,
      // Let the render method that we are going to display the same slide than previously.
      displaySameSlide: true,
      isShowingSwipeAnimation: false,
    }
  }

  public componentDidMount(): void {
    this.setIndexCurrent(this.props.index)
    this.wrapperNode.addEventListener('touchstart', this.handlerSwipeStart, { passive: true })
    this.wrapperNode.addEventListener('touchend', this.handlerSwipeEnd, { passive: true })
    this.wrapperNode.addEventListener('touchmove', this.handlerSwipeMove, { passive: false })
    this.containerNode.addEventListener('transitionend', this.handlerTransitionEnd, { passive: true })

    if (!storageService.getItem(this.tutorialStorageKey) && this.props.slides) {
      delay(4000).then(() => {
        if (!storageService.getItem(this.tutorialStorageKey)) {
          this.startSwipeAnimation()
        }
      })
    }
  }

  public UNSAFE_componentWillReceiveProps(nextprops: IProps): void {
    if (this.indexCurrent !== nextprops.index && nextprops.index !== null) {
      console.log('nextprops', nextprops)
      this.setIndexCurrent(nextprops.index, 'transform 0.35s cubic-bezier(0.15, 0.3, 0.25, 1) 0s', true)
    }
  }

  public componentWillUnmount(): void {
    this.wrapperNode.removeEventListener('touchstart', this.handlerSwipeStart)
    this.wrapperNode.removeEventListener('touchend', this.handlerSwipeEnd)
    this.wrapperNode.removeEventListener('touchmove', this.handlerSwipeMove)
    this.containerNode.removeEventListener('transitionend', this.handlerTransitionEnd)
  }

  public render(): JSX.Element {
    const { children, slides, articleSource } = this.props

    return (
      <div className='swipe-wrapper' ref={el => (this.wrapperNode = el)}>
        <div className='swipe-container' ref={el => (this.containerNode = el)}>
          {slides &&
            slides.map((slide, index) => {
              // here is the condition it will check before rendering 
               return    Math.abs(index - this.state.indexLatest) <= this.props.slideRange ? (
                      <div className='swipe-item ' key={index} style={{position: 'absolute', left: `${100 * index}%`}}>
                        {this.state.isShowingSwipeAnimation && index === this.state.indexLatest && (
                            <Component1/>
                        )}
                        <Component2
                            idURL={slide.idURL}
                            single={false}
                            visible={index === this.state.indexLatest}
                            articleSource={articleSource}
                            count={this.state.indexLatest + 1}
                            total={slides.length}
                        />
                      </div>
                  ) : null
                }
            )}
          {!slides &&
            React.Children.map(children, (child: JSX.Element, index: number) => {
              if (!React.isValidElement(child)) {
                return null
              }
              return (
                <div className='swipe-item ' aria-hidden={index !== this.state.indexLatest} key={index}>
                  {child}
                </div>
              )
            })}
        </div>
      </div>
    )
  }

  private getChildrenCount(): number {
    return this.props.slides ? this.props.slides.length - 1 : React.Children.toArray(this.props.children).length - 1
  }

  private computeIndex = (params: any): { index: number; startX: number } => {
    const startIndex = params.startIndex
    const startX = params.startX
    const pageX = params.pageX
    const viewLength = params.viewLength
    const resistance = params.resistance
    const indexMax = this.getChildrenCount()
    let index = startIndex + (startX - pageX) / viewLength
    let newStartX
    if (!resistance) {
      // Reset the starting point
      if (index < 0) {
        index = 0
        newStartX = (index - startIndex) * viewLength + pageX
      } else if (index > indexMax) {
        index = indexMax
        newStartX = (index - startIndex) * viewLength + pageX
      }
    } else if (index < 0) {
      index = Math.exp(index * RESISTANCE_COEF) - 1
    } else if (index > indexMax) {
      index = indexMax + 1 - Math.exp((indexMax - index) * RESISTANCE_COEF)
    }

    return {
      index,
      startX: newStartX,
    }
  }

  private setIndexCurrent(indexCurrent: number, transition = 'all 0s ease 0s', hasEnded = false): void {
    this.indexCurrent = indexCurrent
    console.log('setIndexCurrent', indexCurrent)

    if (this.containerNode) {
      const transform = `translate3d(-${indexCurrent * 100}%, 0, 0)`
      this.containerNode.style.cssText = `transform: ${transform}; -webkit-transform: ${transform}; transition: ${transition}; -webkit-transition: ${transition};`
    }

    if (hasEnded) {
      if (this.props.onChangeIndex && indexCurrent !== this.state.indexLatest) {
        this.props.onChangeIndex(indexCurrent)
      }

      this.setState({
        indexLatest: indexCurrent,
        isDragging: false,
      })

      if (!storageService.getItem(this.tutorialStorageKey) && this.props.slides) {
        this.stopSwipeAnimation()
      }
    }
  }

  private handleSwipeStart(event: TouchEvent): void {
    const axis = this.props.axis
    const touch = applyRotationMatrix(event.touches[0], axis)
    this.viewLength = this.containerNode.getBoundingClientRect().width
    this.startX = touch.pageX
    this.lastX = touch.pageX
    this.vx = 0
    this.startY = touch.pageY
    this.isSwiping = undefined
    this.started = true

    const computedStyle = window.getComputedStyle(this.containerNode)
    const transform = computedStyle.getPropertyValue('-webkit-transform') || computedStyle.getPropertyValue('transform')

    if (transform && transform !== 'none') {
      const transformValues = transform
        .split('(')[1]
        .split(')')[0]
        .split(',')
      const rootStyle = window.getComputedStyle(this.containerNode)
      const tranformNormalized = applyRotationMatrix(
        {
          pageX: parseInt(transformValues[4], 10),
          pageY: parseInt(transformValues[5], 10),
        },
        axis
      )
      this.startIndex =
        -tranformNormalized.pageX /
          (this.viewLength - parseInt(rootStyle.paddingLeft, 10) - parseInt(rootStyle.paddingRight, 10)) || 0
    }
  }

  private handleSwipeMove(event: TouchEvent): void {
    const { axis, children, resistance } = this.props
    console.log('handleSwipeMove', event,event.touches[0], this.props)
    const touch = applyRotationMatrix(event.touches[0], axis) // We don't know yet.
    const dx = Math.abs(touch.pageX - this.startX)
    const dy = Math.abs(touch.pageY - this.startY)
    const isSwiping = dx > dy && dx > UNCERTAINTY_THRESHOLD // We let the parent handle the scroll.

    if (isSwiping && this.startX > 100 && !(touch.pageX - this.startX > 0 && this.indexCurrent === 0)) {
      event.stopPropagation()
    }

    // The touch start event can be cancel.
    // Makes sure we set a starting point.
    if (!this.started) {
      this.handleSwipeStart(event)
      return
    }

    if (this.isSwiping === undefined) {
      if (
        this.startX < 25 ||
        (this.indexCurrent === 0 && this.startX < touch.pageX) ||
        (this.indexCurrent === this.getChildrenCount() && this.startX > touch.pageX)
      ) {
        this.isSwiping = false
        return
      }

      // We are likely to be swiping, let's prevent the scroll event.
      if (dx > dy) {
        event.preventDefault()
      }

      if (isSwiping || dy > UNCERTAINTY_THRESHOLD) {
        this.isSwiping = isSwiping
        this.startX = touch.pageX // Shift the starting point.

        return // Let's wait the next touch event to move something.
      }
    }

    if (!this.isSwiping) {
      return
    }

    // We are swiping, let's prevent the scroll event.
    event.preventDefault() // Low Pass filter.

    this.vx = this.vx * 0.5 + (touch.pageX - this.lastX) * 0.5
    this.lastX = touch.pageX

    const computeIndex = this.computeIndex({
      children,
      resistance,
      pageX: touch.pageX,
      startIndex: this.startIndex,
      startX: this.startX,
      viewLength: this.viewLength,
    })
    const index = computeIndex.index
    const startX = computeIndex.startX // Add support for native scroll elements.

    if (startX) {
      this.startX = startX
    }

    this.setIndexCurrent(index)

    if (this.state.displaySameSlide || !this.state.isDragging) {
      this.setState({
        displaySameSlide: false,
        isDragging: true,
      })
    }
  }

  private handleSwipeEnd(): void {
    // The touch start event can be cancel.
    // Makes sure that a starting point is set.
    if (!this.started) {
      return
    }

    this.started = false

    if (!this.isSwiping) {
      return
    }

    const indexLatest = this.state.indexLatest
    const indexCurrent = this.indexCurrent
    const delta = indexLatest - indexCurrent
    let indexNew: number

    // Quick movement
    if (Math.abs(this.vx) > this.props.threshold) {
      if (this.vx > 0) {
        indexNew = Math.floor(indexCurrent)
      } else {
        indexNew = Math.ceil(indexCurrent)
      }
    } else if (Math.abs(delta) > this.props.hysteresis) {
      // Some hysteresis with indexLatest
      indexNew = delta > 0 ? Math.floor(indexCurrent) : Math.ceil(indexCurrent)
    } else {
      indexNew = indexLatest
    }

    const indexMax = this.getChildrenCount()
    

    if (indexNew < 0) {
      indexNew = 0
    } else if (indexNew > indexMax) {
      indexNew = indexMax
    }

    this.setIndexCurrent(indexNew, 'transform 0.35s cubic-bezier(0.15, 0.3, 0.25, 1) 0s', true)
  }

  private handleTransitionEnd(event: TouchEvent): void {
    if (event.target !== this.containerNode) {
      return
    }
    if (this.props.onTransitionEnd) {
      this.props.onTransitionEnd(this.indexCurrent)
    }
  }

  private startSwipeAnimation(): void {
    this.setState({ isShowingSwipeAnimation: true })
  }

  private stopSwipeAnimation(): void {
    this.setState({ isShowingSwipeAnimation: false })
    
  }
}
 


      

i tried different things but it didn't help

ossr
  • 41
  • 4

0 Answers0