Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
ReactJS钩子-使用多个useState钩子和样式化组件拖放_Reactjs_Styled Components_React Hooks - Fatal编程技术网

ReactJS钩子-使用多个useState钩子和样式化组件拖放

ReactJS钩子-使用多个useState钩子和样式化组件拖放,reactjs,styled-components,react-hooks,Reactjs,Styled Components,React Hooks,我对钩子相当陌生,我正在尝试实现一个拖放容器组件,该组件在整个鼠标移动过程中处理onDragStart、onDrag和onDragEnd函数。我一直在尝试使用钩子复制这里找到的代码: 使用下面的代码,我几乎可以让它工作了。它使用样式化的组件设置动画。问题是,只有缓慢移动鼠标,它才能工作。如果快速移动鼠标,SVG或此div中包含的任何内容都将抛出屏幕 我有一个component.js文件 import React, { useState, useEffect, useCallback } from

我对钩子相当陌生,我正在尝试实现一个拖放容器组件,该组件在整个鼠标移动过程中处理onDragStart、onDrag和onDragEnd函数。我一直在尝试使用钩子复制这里找到的代码:

使用下面的代码,我几乎可以让它工作了。它使用样式化的组件设置动画。问题是,只有缓慢移动鼠标,它才能工作。如果快速移动鼠标,SVG或此div中包含的任何内容都将抛出屏幕

我有一个
component.js
文件

import React, { useState, useEffect, useCallback } from 'react';
import { Container } from './style'

const Draggable = ({children, onDragStart, onDrag, onDragEnd, xPixels, yPixels, radius}) => {
  const [isDragging, setIsDragging] = useState(false);
  const [original, setOriginal] = useState({
    x: 0,
    y: 0
  });
  const [translate, setTranslate] = useState({
    x: xPixels,
    y: yPixels
  });
  const [lastTranslate, setLastTranslate] = useState({
    x: xPixels,
    y: yPixels
  });

  useEffect(() =>{
    setTranslate({
      x: xPixels,
      y: yPixels
    });
    setLastTranslate({
      x: xPixels,
      y: yPixels
    })
  }, [xPixels, yPixels]);

  const handleMouseMove = useCallback(({ clientX, clientY }) => {

    if (!isDragging) {
      return;
    }
    setTranslate({
      x: clientX - original.x + lastTranslate.x,
      y: clientY - original.y + lastTranslate.y
    });
  }, [isDragging, original,  lastTranslate, translate]);



  const handleMouseUp = useCallback(() => {
    window.removeEventListener('mousemove', handleMouseMove);
    window.removeEventListener('mouseup', handleMouseUp);

    setOriginal({
      x:0,
      y:0
    });
    setLastTranslate({
      x: translate.x,
      y: translate.y
    });

    setIsDragging(false);
    if (onDragEnd) {
      onDragEnd();
    }

  }, [isDragging, translate, lastTranslate]);

  useEffect(() => {
    window.addEventListener('mousemove', handleMouseMove);
    window.addEventListener('mouseup', handleMouseUp);

    return () => {
      window.removeEventListener('mousemove', handleMouseMove);
      window.removeEventListener('mouseup', handleMouseUp)
    };
  }, [handleMouseMove, handleMouseUp]);

  const handleMouseDown = ({ clientX, clientY }) =>{

    if (onDragStart) {
      onDragStart();
    }
    setOriginal({
      x: clientX,
      y: clientY
    });
    setIsDragging(true);
  };

  return(
    <Container
      onMouseDown={handleMouseDown}
      x={translate.x}
      y={translate.y}
      {...{radius}}
      isDragging={isDragging}
    >
      {children}
    </Container>
  )
};

export default Draggable

因此,我首先从父级传入初始值。我认为我没有正确处理useffect/useState,而且它获取信息的速度不够快

如果有人能帮我解决这个问题,我将不胜感激。再次道歉,但我对使用钩子很陌生


谢谢:)

理想情况下,由于
setState
是异步的,因此您应该将所有状态移动到一个
对象中(如中间示例所示)。然后,您可以利用确保调用
设置状态时,每个
事件侦听器
事件回调
使用的值都是最新的

我认为那篇媒体文章中的例子也有同样的跳跃问题(这可能就是为什么这个例子视频移动物体的速度很慢),但是如果没有一个有效的例子,很难说。也就是说,为了解决这个问题,我删除了
originalX
originalY
lastTranslateX
lastTranslateY
值,因为我们利用了
setState
回调,所以不需要这些值

此外,我将
事件侦听器
/
回调简化为:

  • mousedown
    =>鼠标左键单击保持集
    isDragging
    true
  • mousemove
    =>通过
    clientX
    clientY
    更新鼠标移动
  • mouseup
    =>鼠标左键单击释放将
    isDraging
    设置为false
这确保只有一个事件侦听器实际转换
x
y

如果要利用此示例包含多个圆,则需要重用下面的组件,或者使用
useRef
并使用
refs
移动选定的圆;然而,这超出了你最初问题的范围

最后,我还通过将
styled.div.data.attr
重新构造为一个
函数
,返回带有
CSS
样式
属性,修复了
样式化组件
的弃用问题,而不是带有
样式
属性的
对象
,该属性是返回
CSS
函数

不赞成:

styled.div.attrs({
  style: ({ x, y, radius }) => ({
    transform: `translate(${x - radius}px, ${y - radius}px)`
  })
})`
更新:

styled.div.attrs(({ x, y, radius }) => ({
  style: {
    transform: `translate(${x - radius}px, ${y - radius}px)`
  }
}))`
工作示例


组件/圆

import styled from "styled-components";

const Circle = styled.div.attrs(({ x, y, radius }) => ({
  style: {
    transform: `translate(${x - radius}px, ${y - radius}px)`
  }
}))`
  cursor: grab;
  position: absolute;
  width: 25px;
  height: 25px;
  background-color: red;
  border-radius: 50%;

  ${({ isDragging }) =>
    isDragging &&
    `
    opacity: 0.8;
    cursor: grabbing;
  `}
`;

export default Circle;
import React, { useState, useEffect, useCallback } from "react";
import PropTypes from "prop-types";
import Circle from "../Circle";

const Draggable = ({ position, radius }) => {
  const [state, setState] = useState({
    isDragging: false,
    translateX: position.x,
    translateY: position.y
  });

  // mouse move
  const handleMouseMove = useCallback(
    ({ clientX, clientY }) => {
      if (state.isDragging) {
        setState(prevState => ({
          ...prevState,
          translateX: clientX,
          translateY: clientY
        }));
      }
    },
    [state.isDragging]
  );

  // mouse left click release
  const handleMouseUp = useCallback(() => {
    if (state.isDragging) {
      setState(prevState => ({
        ...prevState,
        isDragging: false
      }));
    }
  }, [state.isDragging]);

  // mouse left click hold
  const handleMouseDown = useCallback(() => {
    setState(prevState => ({
      ...prevState,
      isDragging: true
    }));
  }, []);

  // adding/cleaning up mouse event listeners
  useEffect(() => {
    window.addEventListener("mousemove", handleMouseMove);
    window.addEventListener("mouseup", handleMouseUp);

    return () => {
      window.removeEventListener("mousemove", handleMouseMove);
      window.removeEventListener("mouseup", handleMouseUp);
    };
  }, [handleMouseMove, handleMouseUp]);

  return (
    <Circle
      isDragging={state.isDragging}
      onMouseDown={handleMouseDown}
      radius={radius}
      x={state.translateX}
      y={state.translateY}
    />
  );
};

// prop type schema
Draggable.propTypes = {
  position: PropTypes.shape({
    x: PropTypes.number,
    y: PropTypes.number
  }),
  radius: PropTypes.number
};

// default props if none are supplied
Draggable.defaultProps = {
  position: {
    x: 20,
    y: 20
  },
  radius: 10,
};

export default Draggable;
组件/可拖动的

import styled from "styled-components";

const Circle = styled.div.attrs(({ x, y, radius }) => ({
  style: {
    transform: `translate(${x - radius}px, ${y - radius}px)`
  }
}))`
  cursor: grab;
  position: absolute;
  width: 25px;
  height: 25px;
  background-color: red;
  border-radius: 50%;

  ${({ isDragging }) =>
    isDragging &&
    `
    opacity: 0.8;
    cursor: grabbing;
  `}
`;

export default Circle;
import React, { useState, useEffect, useCallback } from "react";
import PropTypes from "prop-types";
import Circle from "../Circle";

const Draggable = ({ position, radius }) => {
  const [state, setState] = useState({
    isDragging: false,
    translateX: position.x,
    translateY: position.y
  });

  // mouse move
  const handleMouseMove = useCallback(
    ({ clientX, clientY }) => {
      if (state.isDragging) {
        setState(prevState => ({
          ...prevState,
          translateX: clientX,
          translateY: clientY
        }));
      }
    },
    [state.isDragging]
  );

  // mouse left click release
  const handleMouseUp = useCallback(() => {
    if (state.isDragging) {
      setState(prevState => ({
        ...prevState,
        isDragging: false
      }));
    }
  }, [state.isDragging]);

  // mouse left click hold
  const handleMouseDown = useCallback(() => {
    setState(prevState => ({
      ...prevState,
      isDragging: true
    }));
  }, []);

  // adding/cleaning up mouse event listeners
  useEffect(() => {
    window.addEventListener("mousemove", handleMouseMove);
    window.addEventListener("mouseup", handleMouseUp);

    return () => {
      window.removeEventListener("mousemove", handleMouseMove);
      window.removeEventListener("mouseup", handleMouseUp);
    };
  }, [handleMouseMove, handleMouseUp]);

  return (
    <Circle
      isDragging={state.isDragging}
      onMouseDown={handleMouseDown}
      radius={radius}
      x={state.translateX}
      y={state.translateY}
    />
  );
};

// prop type schema
Draggable.propTypes = {
  position: PropTypes.shape({
    x: PropTypes.number,
    y: PropTypes.number
  }),
  radius: PropTypes.number
};

// default props if none are supplied
Draggable.defaultProps = {
  position: {
    x: 20,
    y: 20
  },
  radius: 10,
};

export default Draggable;
import React,{useState,useffect,useCallback}来自“React”;
从“道具类型”导入道具类型;
从“./Circle”导入圆;
常量拖动=({位置,半径})=>{
常量[状态,设置状态]=使用状态({
IsDraging:错,
translateX:position.x,
translateY:position.y
});
//鼠标移动
const handleMouseMove=useCallback(
({clientX,clientY})=>{
if(state.isDraging){
设置状态(prevState=>({
…国家,
translateX:clientX,
translateY:clientY
}));
}
},
[国家统计局]
);
//鼠标左键单击释放
const handleMouseUp=useCallback(()=>{
if(state.isDraging){
设置状态(prevState=>({
…国家,
IsDraging:错误
}));
}
},[state.isDragging]);
//鼠标左键单击保持
const handleMouseDown=useCallback(()=>{
设置状态(prevState=>({
…国家,
伊斯特拉格:是的
}));
}, []);
//添加/清理鼠标事件侦听器
useffect(()=>{
window.addEventListener(“mousemove”,handleMouseMove);
window.addEventListener(“mouseup”,handleMouseUp);
return()=>{
window.removeEventListener(“mousemove”,handleMouseMove);
window.removeEventListener(“mouseup”,handleMouseUp);
};
},[handleMouseMove,handleMouseUp]);
返回(
);
};
//道具类型模式
Draggable.propTypes={
位置:PropTypes.shape({
x:PropTypes.number,
y:PropTypes.number
}),
半径:PropTypes.number
};
//如果未提供道具,则为默认道具
Draggable.defaultProps={
职位:{
x:20,
y:20
},
半径:10,
};
导出默认拖拽;

你能制作一个代码沙盒吗?这将更容易调试。这是codesandbox。。。它似乎不像我在故事书上做的那样平滑,而且增量似乎太大:S添加了一个修复程序,使数字正确添加。如果你试着几乎轻弹鼠标并快速移动它,圆形的div就会远离屏幕。非常感谢!这太神奇了。我非常感激。这一切都很有道理:)