react创建自定义组件_创建一个简单的自定义react钩子以拖动组件

react创建自定义组件

In 2003, noted technologist Murphy Lee presaged our current state of modular component based web applications when he asked:

在2003年,著名的技术专家Murphy Lee在询问时预告了我们当前基于模块化组件的Web应用程序的状态:

Wat da hook gon be?

扫管hook钩坤是吗?

Though adamant that he himself had neither need nor want of hooks, many of the problems web developers face today cannot be solved simply with tracks in the background, their headphones loud and a blunt going round and they gonna rip.

尽管他坚持自己不需要钩子,但Web开发人员如今面临的许多问题无法简单地通过背景音轨,耳机响亮而钝钝的声音来解决。

Since the introduction of Hooks in late 2018, they have become a vital part of the React ecosystem, and no wonder, they’re great.

自2018年底引入Hooks以来,它们已成为React生态系统的重要组成部分,难怪它们很棒。

但是什么是钩子? (But what is a hook?)

A hook can be many things.

钩子可以是很多东西。

Basic hooks provided by React allow you to use stateful logic and lifecycle functions in function components, which prior to their introduction was only available in class based components. There are hooks that allow you to chain callbacks, memoize functions and objects and communicate directly with a ref to the DOM.

React提供的基本挂钩允许您在功能组件中使用状态逻辑和生命周期函数,而在引入它们之前,仅在基于类的组件中可用。 有一些钩子使您可以链接回调,记住函数和对象并直接与对DOM的引用进行通信。

And that’s only the hooks provided out of the box by React. Where hooks really start to shine is when you build them out. There’s a good chance that any piece of lower level logic you want to reuse can be expressed as a custom hook. The React community knows this and has created many custom hooks that you can use right now.

这只是React提供的开箱即用的钩子。 钩子真正开始发光的地方是当您将钩子扩大时。 您要重用的任何较低层逻辑很可能都可以表示为自定义钩子。 React社区知道这一点,并创建了许多您现在可以使用的自定义钩子。

Accessing localStorage?

访问localStorage

Wat Da Hook Gon Be?

达胡寺(Wat Da Hook Gon Be)?

Syncing with the indexDB api?

indexDB API同步?

Wat Da Hook Gon Be?

达胡寺(Wat Da Hook Gon Be)?

Even something as simple as seeing whether or not your computer is online.

甚至只是查看计算机是否在线的简单操作。

Wat. Da. Hook. Gon. Be?

笏。 大。 钩。 刚。 是?

听起来不错! 那么,下载一堆钩子吧? (Sounds great! So, download a bunch of hooks right?)

Well, you can. And if you’re pressed for time that would be my advice. The above hooks and many more like them work well, are tested and should help you solve whatever problem you’re up against.

好吧,可以。 如果您时间紧迫,那将是我的建议。 上面的钩子以及其他类似的钩子都可以正常工作,已经过测试,可以帮助您解决遇到的任何问题。

But that won’ t help you learn how they’re working.

但是,韩元”吨帮助您了解他们是如何工作。

That’s why today I’m going to work with you and help you build your own reusable hook to create draggable components.

这就是为什么今天我将与您合作,并帮助您构建自己的可重用挂钩以创建可拖动组件的原因。

You can find the complete code on GitHub.

您可以在GitHub上找到完整的代码。

1.准备和安装 (1. Prep and Install)

Enter npx create-react-app wat_da_hook_gon_be into your terminal to get started.

在您的终端中输入npx create-react-app wat_da_hook_gon_be开始使用。

Image for post
What is the hook going to be?
什么是钩子?

Download the 200 x 200 px image above and save it to your src folder and rename it to albumcover.jpg, then copy the below text to your App file.

下载上面的200 x 200 px图像并将其保存到您的src文件夹中,并将其重命名为albumcover.jpg ,然后将以下文本复制到您的App文件中。

If you input yarn start into your terminal you should see the picture in the upper left hand corner of your browser.

如果在终端中输入yarn start ,则应该在浏览器的左上角看到图片。

2.添加起始位置和状态 (2. Add starting position and state)

There will be quite a bit going on in the hook we’re building. So, for both of our benefits, I’m going to break things down into a few steps and explain what I’m doing on the way.

我们正在构建的钩子中会有很多事情要做。 因此,为了我们的两个好处,我将把事情分解为几个步骤,并解释我在路上所做的事情。

I know that when I am learning new concepts and techniques, I prefer a slow, step by step explanation. So I’m going to break it down as simply as I can.

我知道,当我学习新的概念和技术时,我希望逐步进行逐步解释。 因此,我将尽可能简单地分解它。

Modify App.js with the following code:

使用以下代码修改App.js

Let’s break down what’s going on here.

让我们分解一下这里发生的事情。

At the top in our first import, we are importing the useState hook.

在第一个导入的顶部,我们将导入useState挂钩。

useState is the workhorse of functional components in React. It accepts one argument, an initial state to use, and returns two values: a variable to represent the piece of state and a function to update it. Upon using the function to update state, a rerender is triggered and anything subscribed to the state variable is updated.

useState是React中功能组件的主力军。 它接受一个参数,要使用的初始状态,并返回两个值:代表状态的变量和更新状态的函数。 使用该功能更新状态时,将触发重新渲染,并更新订阅状态变量的所有内容。

After the inline styles that we set up in our last step, we are destructuring the innerHeight and innerWidth properties from the global window object.

在最后一步中设置了内联样式之后,我们正在从全局window对象中破坏innerHeightinnerWidth属性。

In the next line, we put those destructured values to work setting what will be our initial position value. We divide them by half and then subtract 100 from that. As our image is 200 by 200 pixels, this will set the middle of our picture to the middle of our browser.

在下一行中,我们将那些解构后的值用于设置初始位置值。 我们将它们除以一半,然后从中减去100。 由于我们的图片为200 x 200像素,因此会将图片的中间位置设置为浏览器的中间位置。

Next we have the initial value for useState. First, we have the boolean value isDragging set to false. This will be used to tell whether or not a component is being actively dragged or not. The next three properties will always be plain objects with x and y values in them. These represent the x and y axes of our screen, in pixels. We’ll start with origin at x : 0 and y : 0. translation and lastTranslation, which we will talk more about in a bit, will start at the value set in our startingPosition variable.

接下来,我们有了useState的初始值。 首先,我们将布尔值isDragging设置为false. 这将用于指示组件是否正在被主动拖动。 接下来的三个属性将始终是其中包含x和y值的普通对象。 这些代表我们的屏幕的x和y轴(以像素为单位)。 我们将从x:0和y:0的origin开始。我们将在稍后讨论的translationlastTranslation将从startingPosition变量中设置的值startingPosition

Nothing has changed on the screen just yet, but we are well on our way.

屏幕上尚未发生任何变化,但我们的工作进展顺利。

3.添加handleMouseDown (3. Add handleMouseDown)

A very common pattern when dealing with mouse events is to break down the logic into three functions, handling logic for when a mouse button is clicked, when the mouse is moved and when the mouse button is released. We will be utilizing this pattern with three functions, called handleMouseDown, handleMouseMove, and handleMouseUp.

处理鼠标事件时,一种非常常见的模式是将逻辑分为三个功能:处理单击鼠标按钮,移动鼠标和释放鼠标按钮的逻辑。 我们将通过三个函数来使用此模式,这三个函数分别是handleMouseDownhandleMouseMovehandleMouseUp

Observe, the following code.

观察下面的代码。

Before we start, we’re going to destructure isDragging from our dragInfo state variable to make things just a bit easier to work with.

在开始之前,我们将从我们的dragInfo状态变量中解构isDragging ,以使事情更容易使用。

The handleMouseDown function will accept two arguments, clientX and clientY, destructured from a fired mouse event. These are the coordinates on the X and Y axes at the time we click on the element we would like to drag. Not too complex right?

handleMouseDown函数将接受两个参数, clientX从触发的鼠标事件解构的clientXclientY 。 这些是我们单击要拖动的元素时X和Y轴上的坐标。 不太复杂吧?

If isDragging is set to false, we will proceed into our function. We will call our setDragInfo method to update our dragInfo state, changing isDragging to true and our origin coordinates to clientX and clientY.

如果isDragging设置为false,我们将进入函数。 我们将调用setDragInfo方法来更新dragInfo状态,将isDragging更改为true并将origin坐标更改为clientXclientY

4.添加handleMouseMove (4. Add handleMouseMove)

The handleMouseMove function will fire again and again whenever our mouse is moved, for however long we hold it down. So, I think we should try to get it right, don’t you?

每当我们移动鼠标时, handleMouseMove函数都会一次又一次触发,无论按住多长时间。 所以,我认为我们应该尽力做到正确,不是吗?

Behold!

看哪!

Like our last function, handleMouseMove takes the destructured clientX and clientY properties as arguments. If isDragging resolves to true, the origin and lastTranslation values are destructured from draginfo and we again call our setDragInfo action to update our state. Do you see how this is really just setting up rapid fire updates to state again and again?

像我们的最后一个函数一样, handleMouseMove将经过解构的clientXclientY属性作为参数。 如果isDragging解析为true ,那么originlastTranslation值将从draginfo然后再次调用setDragInfo操作以更新状态。 您是否看到这真的只是在设置快速更新以反复陈述状态?

The only value we’re interested in changing right now istranslation. We’ll add the origin values we stored during our mouseDown function, add them to our last translation value and subtract that from the client argument values fired from the mouse event. To avoid getting negative values we’ll wrap that whole equation in Math.abs. This calls the absolute value, so only positive values will return from this function, and therefore it will stay on the screen.

现在,我们唯一想改变的价值是translation 。 我们将添加在mouseDown函数期间存储的origin值,将它们添加到最后的转换值,然后从mouse事件中触发的client参数值中减去这些origin值。 为了避免得到负值,我们将整个方程式包装在Math.abs 。 这将调用绝对值,因此此函数将仅返回正值,因此它将保留在屏幕上。

In the next step we’ll be attaching the translation value directly to CSS values on our draggable object, updating them on every render.

下一步,我们将translation值直接附加到可拖动对象上CSS值上,并在每个渲染器上对其进行更新。

5. handleMouseUp并将其捆绑在一起 (5. handleMouseUp and tying it all together)

For our last and final function, we will not be needing any arguments, as all we’re going to do is turn off our dragging and set a value to be used for our next drag.

对于我们最后的遗愿功能,我们会不会需要任何参数,如我们所要做的是关掉我们的拖动,并设置用于我们的下一个阻力值。

To do this, once again if our isDragging variable resolves to true, we will destructure translation from dragInfo. Remember that this is the value we just changed many, many times during our handleMouseMove function. Again, calling our setDragInfo method, we will change isDragging to false, ending the drag cycle, set the lastTranslation value to the last returned value of translation from handleMouseMove and spread the rest.

为此,如果isDragging变量解析为true ,我们将再次从dragInfo解构translation 。 请记住,这是我们在handleMouseMove函数中多次更改的值。 同样,拨打我们的setDragInfo方法,我们将改变isDraggingfalse ,结束拖周期,设置lastTranslation值的最后一个返回值translationhandleMouseMove和传播休息。

Yes! It really is that simple. Pretty much it’s just updating x and y values with the mouse. But before it will work, we’ll need to attach all those to our elements somehow. We do this with the inline style variable picturePosition. It changes our position rule to absolute and attaches the right and bottom rules to the x and y values of translation. Since it is generated with every render, it will generate a fresh position for our dragged item as we drag it.

是! 真的就是这么简单。 差不多只是用鼠标更新x和y值。 但是在它起作用之前,我们需要以某种方式将所有这些附加到我们的元素上。 我们使用内联样式变量picturePosition进行此picturePosition 。 它将position规则更改为absolute规则,并在translation的x和y值上附加了right规则和bottom规则。 由于它是在每个渲染器中生成的,因此在我们拖动项目时,它将为我们拖动的项目生成一个新位置。

After that, it’s a simple matter of spreading the inline style objects in picturePosition and pictureStyle and attaching mouse events to the appropriate synthetic event listeners on the element we wish to be dragged.

之后,只需将内联样式对象分布在picturePositionpictureStyle然后将鼠标事件附加到我们希望拖动的元素上的适当合成事件侦听器上,就很简单。

But wait a minute, why are there two events attached to handleMouseMove? When the mouse leaves the element, don’t we want it to, you know, leave?

但是请稍等,为什么handleMouseMove附加两个事件? 当鼠标离开元素时,我们不希望它离开吗?

Try using this code without that listener. It will work, mostly. The problem is when you move the pointer too fast, often the mouse will move faster than the functions can keep up with and you will lose the drag. Or, you won’t lose the drag but other strange behaviors may happen, like no longer being able to hover over the element. Attaching handleMouseMove to both onMouseMove and onMouseLeave eliminates this headache. And since we’re using a boolean to detect whether a drag is happening, we don’t have to worry about a drag state getting stuck into a permanent ‘on’ position.

尝试在没有该侦听器的情况下使用此代码。 它将大部分起作用。 问题是,当您将指针移动得太快时,鼠标移动的速度通常会超过功能所能跟上的速度,并且会丢失拖动。 或者,您将不会失去阻力,但是可能会发生其他奇怪的行为,例如不再能够将鼠标悬停在元素上。 将handleMouseMove附加到onMouseMoveonMouseLeave消除这种麻烦。 而且,由于我们使用布尔值来检测是否发生拖动,因此我们不必担心拖动状态会卡在永久的“打开”位置。

And that’s it! One draggable component attached to one element!

就是这样! 将一个可拖动组件附加到一个元素上!

It’s not very modular though. In our next step we’ll see where hooks really shine and abstract it out into a reusable useDrag hook

虽然不是很模块化。 在下一步中,我们将看到钩子真正发光的地方,并将其抽象为可重复使用的useDrag钩子。

6. useDrag (6. useDrag)

Create a new file in your src folder called useDrag and move the following code into it.

src文件夹中创建一个名为useDrag的新文件,并将以下代码移入其中。

Here we’ve taken all the logic around dragging out our component, and put it into a place where we can reuse it again and again whenever we need it.

在这里,我们采用了拖出组件的所有逻辑,并将其放到一个可以在需要时重复使用的地方。

After you’ve done that, you can change App to the following.

完成此操作后,可以将App更改为以下内容。

最后的想法 (Final Thoughts)

Today we’ve how to make any element draggable with a simple three function process to handle mouse down events, mouse move events and mouse up events. We’ve also learned how to abstract that pattern into a reusable hook, so we can utilize it for any component we need. I hope this article has been enjoyable and informative for you, and you enjoyed reading it as much as I did writing it.

今天,我们已经通过一个简单的三功能过程使任何元素都可拖动,以处理鼠标按下事件,鼠标移动事件和鼠标按下事件。 我们还学习了如何将该模式抽象为可重用的钩子,以便可以将其用于所需的任何组件。 我希望本文对您来说是愉快和有益的,并且您喜欢阅读它,就像我写它一样。

翻译自: https://medium.com/@timmalstead/create-an-easy-custom-react-hook-for-dragging-components-3779b30d08b5

react创建自定义组件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值