钩中的延迟状态更改

时间:2019-05-06 12:45:54

标签: javascript reactjs

因此,我最近开始将某些功能更改为hook's,其中一种功能应该从slides array加载某些组件,从currentSlide获取位置编号,然后创建结合这两者的标签名称。

import React, { useReducer, useRef } from "react";

const initialState = {
    slides: ['Slide1','Slide2','Slide3'],
    currentSlide: 0,
    initialX: 0,
    endX: 0
}

const reducer = (state, action) => {
    switch (action.type) {
        case 'pull-slides':
            return { ...state, slides: action.value };
        case 'swipe-right':
            return { ...state, currentSlide: state.currentSlide + 1 }
        case 'swipe-left':
            return { ...state, currentSlide: state.currentSlide - 1 }
        case 'set-initialX':
            return {
                ...state, initialX: action.position
            }
        case 'set-endX':
            return {
                ...state, endX: action.position
            }
        default:
            throw new Error('Unexpected action');
    }
}

const swipeDetection = () => {
    const [state, dispatch] = useReducer(reducer, initialState)
    const swipeArea = useRef(null)

    function _onMouseDown(e) {
        console.log(e.screenX)
        dispatch({ type: 'set-initialX', position: e.screenX })
        console.log(state)
    }

    function _onMouseUp(e) {
        console.log(e.screenX)
        dispatch({ type: 'set-endX', position: e.screenX })
        console.log(state)

        if ((state.initialX < state.endX) && ((state.endX - state.initialX) > 350)) {
            console.log('right')
            if (state.currentSlide < (state.slides.length - 1)) {
                console.log('right')
                dispatch({ type: 'swipe-right' })
            }
        } else if ((state.initialX > state.endX) && ((state.initialX - state.endX) > 350)) {
            console.log('left')
            if (state.currentSlide > 0) {
                dispatch({ type: 'swipe-left' })
               console.log('left')
            }
        }
    }

    const TagName = state.slides[state.currentSlide]

    return (
        typeof TagName == 'function' ? (
            <div className="h-100" ref={swipeArea} onMouseDown={_onMouseDown} onMouseUp={_onMouseUp}>
                <TagName />
            </div>
        ) : ''
     )
}

export default swipeDetection

为了从一个组件切换到另一个组件,我决定使用onMouseDown / onMouseUp而不是onMouseMove事件。

因此,当您单击鼠标时,它会存储screenX,而当您释放鼠标时,它会再次存储screenX,并比较这两个值以查看您已滑过 左或右。

根据我的判断,这似乎工作得很好,除了您必须在一个方向上滑动两次以使其实际更改 currentSlide值。

我不知道为什么会这样,因为我对Hooks确实很陌生,而我只是得到了我的 code-legs (像是见解,但对于程序员来说呢?)

我尝试了不同的方法和材料,但是我真的找不到与我的案子相关的任何东西,没有关于为什么会发生这种情况的任何想法?

我为console.loge.screenX添加了state,以查看点击时发生了什么,因此当您单击它时,它会立即返回e.screenX值和state,但由于某些原因state的值未更新...

1 个答案:

答案 0 :(得分:1)

dispatch(就像setState以及对React进行更新的任何其他调用一样)被推迟,因此不会立即运行。另外,分派会导致重新渲染,该渲染将再次执行整个组件函数,这将在其中创建一个新的state变量。无论您做什么,state都将始终指向旧状态。因此:

   state.initialX < state.endX

将始终在先前状态下运行。要解决此问题,请执行以下操作:

1)从状态中删除endXendY。如果手指抬起,则需要立即检查是否有滑动。无需坚持该职位。

2)减速器仅需要两个事件:触地和触地。其他所有操作都应在减速器内部完成。

    const SlideSwiper = ({ slides }) => {
      const [{ currentSlide }, touch] = useReducer(({ currentSlide, start }, { type, position }) => {
         if(type === "up") {
           if(Math.abs(position.x - start.x) < 350 && Math.abs(position.y - start.y) < 350)
             return { currentSlide };
           }

           // TODO: Additional logic for swiping up & down?

           return { currentSlide: currentSlide + (position.x > start.x ? 1 : -1), start: null };

         } else if(type === "down") {
           return { currentSlide, start: position };
         }
      }, { currentSlide: 0, start: null });

      const touchDown = e => touch({ type: "down", position:  { x: e.clientX, y: e.clientY }});
      const touchUp = e => touch({ type: "up", position:  { x: e.clientX, y: e.clientY }});

      const slide = slides[currentSlide];
      //...
  });