The small voice BB

In the process of translation, I will add a lot of my personal explanations (in brackets, like this) and some jokes of my own on the premise of ensuring that the meaning is accurately conveyed

After half a year, I click on the react-Dnd website again because I really want to use this plugin recently. It seems that I have dug a hole before and left it unfilled. This time, taking advantage of the demand rectification period after the successful quarrel with the product, to fill the translation pit.

Prospects for the feed

Personal problem: The original text uses a lot of the first person, the translation attempt to use the first person plural to narrow the distance between readers, but failed! So it’s still translated into the first person singular.

Some bugs: there are some undefined variables introduced in the demo code, if there is a problem with the demo you can refer to this issue to solve it, if you can’t solve it you can leave a comment below (lol, as if your article is really read)~

The code in this article is screenshots: The code is screenshots for two reasons:

  • This theme displays ugly code;
  • If you accidentally click on this article, you can manually type the code and follow the tutorial.

Rules of chess game: help you baidu dig friends

The result:

👍👍👍👍 👍👍👍👍 👍

The translation

React DnD

The tutorial

Now that you’ve read the overview section, it’s time to take the plunge!

Here, I’m going to use React and React-DND to make a chess game! Just kidding, making a complete chess game is beyond the tutorial’s goal, I’m going to make a board and a lone knight. The knight can drag according to the rules of chess.

If you’re already familiar with React, you can skip to the section on adding drag-and-drop interactions (skip not recommended; there are some ideas to learn about the chessboard going from 0 to 1).

I’ll use this example to show you the data-driven ideas of React-DND. You’ll learn how to create drag items and drop containers, how to associate them with your components, and then see how they interact with drag events.

Let me begin! (rubbing)

Environment to prepare

In this tutorial, the code examples use functional components and modern JavaScript syntax. We recommend that you use build tools to translate these new syntax features to match your development environment. I recommend using create-react-app directly.

You can get a preview of what to do here.

Start the whole!

Define the components

Let’s start by creating some components. Let’s put the drag-and-drop thing aside. What components do you need if you want to implement drag-and-drop? Here are a few that come to mind:

  • Knight: Lone knight chessman;
  • SquareA small square on a chessboard;
  • Board: a chessboard with 64 squares;

Think about what their props are going to be.

  • KnightIt could be a stateless component. It has onelocationProperty, butKnightYou don’t need to know, you can passSquareTo locate the child elementKnightThe location (i.e. throughpropspositionPass in).
  • Can be achieved bypropsthelocationTo pass toSquare(then passed to Knight), but not necessary. becauseSquareThe only information needed is the background color it is rendering. Can put theSquareSet the background color to white, then add an optional black as optionalprops. Of course,SquareThere may be a child node, which is the chess piece currently in the grid, and the chess piece chooses a white as its default color to match the browser’s default color.
  • BoardThe components are a little tricky. theSquareComponents aschildrenThere’s no point in passing it onBoardUse it as a container component{props.children}To renderSquare), becauseBoardWhat else is there in the component itself? It is onlySquareComponent, which also needs to containKnightBecause theKnightComponents need to be placed inSquareComponent inside. This means thatBoardComponents need to knowKnightCurrent location. In a real chess game,BoardYou need to receive a data set describing the colors and positions of all the pieces. But for this example, oneknightPositionpropIt is more convenient. I’m going to use a length of2Array as the chessman coordinates,[0, 0]saidA8The grid of coordinates, why[0, 0]saidA8Don’t sayA1? Coordinate matching is used to match the coordinate orientation of the browser[0, 0]To the correspondingA1It gives me a headache(Below is a picture to understand the position of A8 and A1.)

So where do I put state? I really don’t want to put them in the Board component. It’s also a good idea to put some state in child components if possible. Also, the Board component already has some typographical logic, so I don’t want it to manage state anymore.

The good news is, that’s not what I’m thinking about right now. I just write first and don’t care where the state is, render things correctly first, and then worry about managing the state.

Create components

I prefer to write from the bottom up because I can see the effect as I go along. If you start with the Board component, there is nothing on the page until you finish writing Square. The other thing is THAT I can see Square as I write without thinking about Board. I think this kind of immediate feedback is very necessary. So I started with Knight. It doesn’t have any props, so it’s easy to do:

♘ is a Unicode encoded chess piece! Very handsome. I could have used the color as the props property for the pieces, but in this example there won’t be any black pieces, so I don’t need to. This looks like it will run, so just to make sure it works, change the mounted component and render it to test it out.

I do this every time I write a component, so I have something to render every time. For large app development, I use something like the Cosmos component library (a sandbox environment for developing and testing components) so I don’t have to write around wondering what the components will look like. With Knight on the screen, it’s time to implement Square. Here’s my first try.

Then I changed the mounted components to see what Knight looked like inside Square:

Oh ho, the page did not render successfully. I made a few small mistakes:

  • Don’t giveSquareAny size. I don’t want to letSquareIt’s a fixed size, so I’ll give you awidth:'100%'height:'100%'.
  • Forget theSquaredivadd{children}, soKnightIt’s ignored and not rendered.

After these two errors were corrected, the checkers were black and I still couldn’t see my pieces. Because the default browser text is black, you can’t see the pieces in the black checkers. Knight could be given color props to fix this, but an easier fix would be to set the text color where the backgroundcolor is set. This allows Square to fix these errors while still being compatible with both black and white.

Finally, time for the Board section! First I’ll write a simple version – just return a Square.

So far, all I need is for it to render successfully in the page before I can proceed to the next step:

Indeed, you can now see a checker box. Now I need to add a bunch of checkers! But where to start? What do YOU want to put in the Render method? The for loop? Or map loop through an array? Honestly, I don’t need to think about that right now. I already know how to render different states of checkers. I also know the coordinate positions of the pieces through knightPosition. This means that I can write a renderSquare method to renderSquare, leaving aside how to render Board. My first attempt at writing a renderSquare method looked like this:

Try changing the Board rendering method to the following

At this point, I notice that I haven’t added any layout to my squares. I useflexLayout, add some styles to the rootdivAnd then theSquaredivSo you can wrap itSquareLet’s line it up. In general, though, you need to add extradivWrap the component, but it’s still a good idea to wrap the component into a component that doesn’t need to care about its internal layout.

It looks very good! I don’t know how to constrain the Board to maintain the aspect ratio of the checkers, but that should be easy to add later.

Recall that I started at 0 and now can move Knight on Board by changing knightPosition:

The declarativeness is fantastic! That’s why people love working with React.

addGameState manager

I want to be able to drag this piece. To do this, I need to store the knightPosition in state, and there are ways to change it.

Because setting up the state stuff takes a little bit of thinking, I’m not going to try to figure out how to drag at the same time. Instead, I’ll start with a simpler implementation. When you click on a board, I move the pieces over. But the rules of chess need to be followed. Implementing this logic requires me to know enough about managing state to use drag and drop instead of clicking after I’m done with the logic.

React supports a variety of state management and data flow tools; You can use Flux,Redux,Rx or ~~Backbone~~ to avoid fat models and separate your reads from writes.

I don’t want to install or set up Redux for this simple example, so I’ll use a simpler mode. It’s not as comprehensive as Redux, but I don’t need it to be. I haven’t decided on the API for my state manager yet, but I’ll call it Game for now, and it definitely needs some way to signal data changes to my React code.

With that in mind, I can rewrite my index.js to introduce a Game that doesn’t yet exist. Notice that I’m tinkering with code and can’t run because I don’t know what API to export from Game.

What is the observe function I imported? This is the easiest way I can think of to subscribe to an ever-changing state. I could turn it into an EventEmitter, but why should I when all I need is a single changing event? I could make Game into an object model, but all I need is a simple set of values. Why do I need to do that?

To verify that the subscription API works, I’ll write a Game that returns a random location:

Get the project running again without poking!

If I want some interaction, I need to find a way to change the Game’s state in the Component. Now, I’m going to change the internal state as simply as possible by directly exposing a MoveKnight method. In slightly more complex applications, where a single user action might cause several different state changes, this wouldn’t work, but it didn’t in my example.

Now back to my component. The current goal is to move the piece to the square I clicked on. One way is to call the moveKnight method within the Square component. However, this would require me to pass the location to Square. Here’s a good rule of thumb:

If a component doesn't need some data when rendering, it doesn't need that data at all.Copy the code

The Square component does not need to know the positions of the pieces to render. So it’s best to avoid coupling the MoveKnight method to the Square component. Instead, I add an onClickhandler method on the div that wraps Square in the Board component.

I could have added an onClickprop to Square instead, but since I’m going to remove click-handling events later in favor of a drag-and-drop interface, why?

Now the last part is to examine the rules of chess. Pieces (horses) are not allowed to move to any square, only L-shaped moves are allowed. I added a canMoveKnight(toX, toY) function to the Game and changed the initial position to B1 to match the chess rules:

Finally, I washandleSquareClickMethodcanMoveKnightcheck:

So far so good!

Add drag and drop interactions

This is the part that really motivated me to write this tutorial. We’ll now see how easy it is to add some drag-and-drop interactions to existing components using React DnD. This section assumes that you already have some knowledge of the concepts mentioned in overview, such as Backends, collecting functions, types, items, Drag sources, drop targets. If you don’t know anything about these things, it’s okay to give them a chance (check it out!) before you start coding. . Start by installing React DnD and HTML5 Backend:

npm install react-dnd react-dnd-html5-backend
Copy the code

In the future, you may want to explore alternative third-party backends, such as Touch Backend, but that is beyond the scope of this tutorial.

Set the drag context

The first thing we need to set up in our application is DndProvider. The DndProvider should be mounted at the top of our application (outside the root APP) to indicate that we want to use HTML5Backend.

Define drag types

Next, I create constants for the draggable ItemTypes. There is only one Itemtype in our game, the lone knight piece. Create a Constants object and export:

All set, let’s give Knight a buff so he can drag!

Get the horse running

UseDraghook accepts a memoization function that returns a particular format object. In this particular format object, item.type is set to the constant we just defined. Now, we need to write a collection function.

Let’s savor:

  • UseDrag takes an object of a specific format as an argument. The value of item.type is required. It specifies the type of item to drag. We can also add additional information here to identify the type of other pieces being dragged. But since this is a toy application, we only need to define this one type.

  • Collect defines a collector function that converts the states in the drag system into props that can be used by components.

  • The result array includes:

    • The first entry in the array is onepropsObject – contains data fromDrag and drop systemAll properties collected in.
    • The second entry in the array is aref function. This method is used to makeDom elementsreact-dndMake connections.

Now that the Knight component has added the useDrag call and updated the Render method, let’s see what it looks like:

Enable Board Squares to be placed

Knight is now a draggable item, but there are currently no containable containers. Let’s go ahead and make Square a placable container.

This time we will inevitably need to pass the location property to Square. After all, Square can’t know how to place a dragged piece if it doesn’t know where it is. But on the flip side, that’s not true either, because Square is still the same whole thing in our app. It was just a simple component before, so why make it complicated? When faced with this dilemma, it is time to split the stateful and stateless components.

I’m going to introduce a new component called BoardSquare. It both renders the previous Square and knows its location. In fact, it encapsulates some of the logic that renderSquare used to do inside the Board. When appropriate, you can usually extract React components from such rendering methods.

Here are the components I extracted:

I also modified the Board component:

Now we wrap the BoardSquare component with the useDrop hook. I’m going to write a deployable container that handles only drop events:

See? The drop method gets the props property of BoardSquare, so the container knows where to move the pieces when they drop. In a real application, I might also use monitor.getitem () to retrieve the dragged item returned from the beginDrag, but since we only have one dragable thing in the entire application, I don’t need to do that.

In my collection function, I will ask the listener if the mouse is on BoardSquare, once again I decide whether to highlight it or not.

This is what BoardSquare looks like after modifying the Render method to attach the placable container and show the highlighted mask:

This is starting to get really good! One step away from completing the tutorial. We want to highlight the moveable checkers as we drag the pieces, and only deal with them when they land on a valid checkerdropEvents. Thankfully, withReact DnDIt’s really easy to do that. I just need to define one in my deployable container configurationcanDropThe method will do.

I also added monitor.candrop () to my collection function, along with some highlight-mask rendering logic to the component:

Add a drag preview image

The last thing I want to demonstrate is the customization of dragging preview images. Of course, browsers take screenshots of DOM nodes, but what if we want to display a custom image? We were lucky because React DnD was easy to do. We just need to use the Preview ref provided by the useDrag hook. . The Preview ref lets us attach a dragPreview in the render function, just like we used to define dragable items. React-dnd also provides a utility component, DragPreviewImage, which can use this ref to display an image as a drag preview.

conclusion

This tutorial guides you through creating the React component, making design decisions about the component and applying state, and finally adding the Drag and drop interaction. The purpose of this tutorial is to show you that React DnD fits the React philosophy very well, and that you should consider the architecture of your application before diving into complex interactions. Happy dragging and dropping.

Conclusion the translator

The react-DND tutorial is part of the documentation, which starts with a small demo. In the demo, the React component design idea and the state management split are interspersed. The full text not only describes the related API of React-DnD, but also shows us a vivid and rich ecosystem built by React. The translator pays attention to the letter, expressiveness and elegance, and gropes his way slowly. Self-knowledge has not reached the level of belief, especially in technical articles, there are many special meanings in the technical circle, sometimes can not be found by looking up the dictionary, this can only be accumulated slowly.

~peace~