javascript - 如何使用 React Hooks 处理 React Svg 拖放
问题描述
我正在尝试在 SVG 形状上实现拖放。我成功地使它与使用类组件一起工作。这是代码沙箱的链接: https ://codesandbox.io/s/qv81pq1roq
但是现在我想通过使用带有自定义 Hook 的新 React api 来提取这个逻辑,该 Hook 能够将此功能添加到功能组件中。我尝试了很多东西,但没有任何效果。这是我最后一次尝试:
https://codesandbox.io/s/2x2850vjk0
我怀疑我添加和删除事件侦听器的方式有些问题......所以这是我的问题:
你认为,有可能把这个 DnD SVG 逻辑放到一个自定义 Hook 中吗?如果是,你知道我做错了什么吗?
解决方案
我在这里修复了这个例子 - https://codesandbox.io/s/2w0oy6qnvn
您的钩子示例中有许多问题:
setPosition
不同于setState
. 它不会进行浅合并,而是将整个对象替换为新值,因此您必须使用Object.assign()
或扩展运算符与先前的值合并。此外,setPosition()
如果您需要在设置新值时引用它,则该钩子采用一个回调值,该值提供先前的状态值作为第一个参数。与类不同,该
handleMouseMove
函数在每次渲染中都会重新创建,因此在调用时document.removeEventListener('mousemove', handleMouseMove)
不再引用初始handleMouseMove
值document.addEventListener('mousemove', handleMouseMove)
。解决方法是使用useRef
它创建一个在组件的整个生命周期中持续存在的对象,非常适合保留对函数的引用。中的事件参数
handleMouseDown
和您引用的事件参数setPosition
不同。因为 React 使用事件池并重用事件,所以 in 中的事件setPosition
可能已经与传入的事件不同handleMouseDown
。解决这个问题的方法是首先获取 和 的值,pageX
以便pageY
在setPosition
其中不需要依赖事件对象。
我用您需要注意的部分注释了下面的代码。
const Circle = () => {
const [position, setPosition] = React.useState({
x: 50,
y: 50,
coords: {},
});
// Use useRef to create the function once and hold a reference to it.
const handleMouseMove = React.useRef(e => {
setPosition(position => {
const xDiff = position.coords.x - e.pageX;
const yDiff = position.coords.y - e.pageY;
return {
x: position.x - xDiff,
y: position.y - yDiff,
coords: {
x: e.pageX,
y: e.pageY,
},
};
});
});
const handleMouseDown = e => {
// Save the values of pageX and pageY and use it within setPosition.
const pageX = e.pageX;
const pageY = e.pageY;
setPosition(position => Object.assign({}, position, {
coords: {
x: pageX,
y: pageY,
},
}));
document.addEventListener('mousemove', handleMouseMove.current);
};
const handleMouseUp = () => {
document.removeEventListener('mousemove', handleMouseMove.current);
// Use Object.assign to do a shallow merge so as not to
// totally overwrite the other values in state.
setPosition(position =>
Object.assign({}, position, {
coords: {},
})
);
};
return (
<circle
cx={position.x}
cy={position.y}
r={25}
fill="black"
stroke="black"
strokeWidth="1"
onMouseDown={handleMouseDown}
onMouseUp={handleMouseUp}
/>
);
};
const App = () => {
return (
<svg
style={{
border: '1px solid green',
height: '200px',
width: '100%',
}}
>
<Circle />
</svg>
);
};
ReactDOM.render(<App />, document.querySelector('#app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>
推荐阅读
- javascript - 有没有办法使用字符串为对象的深层嵌套属性赋值?
- c# - 订阅方法执行c#
- java - GXT 如何在 XTemplate 中显示树对象?
- spring - 可以使用 Intellij Scratch 文件通过 JpaRepository 接口进行查询吗?
- jquery - 如何在不使用scrollY的情况下垂直修复数据表标题?
- r - 在 data.tables 中创建新列时如何使用向量化的 get() 函数?
- python - TypeError: "'int' object is not callable", '发生在索引 0'
- hybris - 登录用户时出现 StackOverflowError,该用户应该在 Backoffice 资源管理器树中查看特定节点
- typescript - 在组件上使用 v-for 的反应式列表
- git - Katalon Studio 和 Git SubModules:如何将外部公共库导入到 katalon 项目中