drop(props, monitor, component)
๋ฉ์๋์๋ ์ธ ๊ฐ์ ์ธ์๊ฐ ์์ต๋๋ค. ๊ทธ๋ฌ๋ canDrop(props, monitor)
์๋ component
์ธ์๊ฐ ์์ต๋๋ค.
ํญ๋ชฉ์ ๋ค๋ฅธ ๊ตฌ์ฑ ์์ ์๋ก ๋๋๊ทธํ ๋ ํด๋น ๊ตฌ์ฑ ์์๋ฅผ 50%(๋์ด)์ ๋ ๋ถ๋ถ์ผ๋ก "๋ถํ "ํ๊ณ ์ถ์ต๋๋ค. ์์ดํ ์ ๋์ ๋ถ๋ถ์ ๋จ์ด๋จ๋ฆฌ๋ฉด ๊ทธ ์์ ๋์ ๊ฒ์ด๊ณ , ๋ฎ์ ๋ถ๋ถ์ ๋์ผ๋ฉด ๊ทธ ๋ค์ ๋์ผ ๊ฒ์ ๋๋ค.
๊ตฌ์ฑ ์์๊ฐ ์๋จ/ํ๋จ ๋ถ๋ถ์ ๋๋กญ๋์๋์ง ์ฌ๋ถ๋ฅผ ๊ฐ์งํ๋ ์ฝ๋๊ฐ ์ด๋ฏธ ์์ต๋๋ค. ๋ด๊ฐ ์ง๊ธ ์ํ๋ ๊ฒ์ ๋ง์ฐ์ค๊ฐ ์๋จ/ํ๋จ ๋ถ๋ถ์ ์๋์ง ์ฌ๋ถ์ ๋ฐ๋ผ ํด๋์ค๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ๋๋ค(๊ทธ๋ฌ๋ ๋๋กญ ๋์์ด ์๋ ํธ๋ฒ ๋์ ์ค์).
hover(props, monitor, component)
๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์๋์ง ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. ์๋ํ๋ฉด DOM์ CSS ํด๋์ค๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ์ด์ ์ ์ฌํ ๊ตฌ์ฑ ์์์ ์์ฑ์ ์ถ๊ฐํ๋ ๋ฐฉ๋ฒ์ ์์ง ๋ชปํ๊ธฐ ๋๋ฌธ์
๋๋ค. ๊ตฌ์ฑ ์์ ์์ฒด์ ์ํ์ง ์๊ณ ํด๋น ์ปจํ
์คํธ ๋ฑ์ ์ก์ธ์คํ ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค.
๋ด๊ฐ ๋ญ๊ฐ๋ฅผ ๋์น๊ณ ์๋ ๊ฒ ๊ฐ์. :)
์ด๋ด, ๋น์ ์ ์ด์ด ์ข๋ค! ๋๋ ์ด๊ฒ์ ๊ฑฐ์ ์ ํํ๊ฒ ๊ตฌํํ ์ ์ด ์์ผ๋ฏ๋ก ๋ช ๊ฐ์ง ์ฝ๋๋ฅผ ํจ๊ป ๋ณด๊ฒ ์ต๋๋ค.
์ข์ต๋๋ค. ๋ฐ๋ผ์ ์์ด๋์ด๋ ๊ตฌ์ฑ ์์์์ ์ํ๋ฅผ ์ค์ ํ๊ณ ์ํ๊ฐ ์ค์ ๋๋ฉด ํด๋์ค๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ๋๋ค.
Foo๋ฅผ Bar๋ก ๋๋๊ทธํ๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค.
import React, { Component } from "react";
import classNames from "classnames";
class Bar extends Component {
constructor(props) {
super(props);
this.state = {
// Where a foo is hovering over the component. One of null, "above", or "below"
fooHover: null,
};
}
render() {
const { fooHover } = this.state;
const classes = classNames("bar", {
"bar-above": fooHover === "above",
"bar-below": fooHover === "below",
});
}
}
์ ์ผํ ์ง๋ฌธ์ ๊ทธ ์ํ๋ฅผ ์ด๋ป๊ฒ ์ค์ ํ๋๋๋ ๊ฒ์ ๋๋ค!
import { findDOMNode } from "react-dom";
const barTarget = {
...
hover(props, monitor, component) {
if (!monitor.canDrop()) {
return;
}
const rawComponent = undecorate(component); // undecorate described below
const { y } = monitor.getClientOffset();
const { top, height } = findDOMNode(component).getBoundingClientRect();
if (y < top + height/2) {
rawComponent.setFooHover("above"); // setFooHover described below
} else {
rawComponent.setFooHover("below");
}
},
...
}
๋ฐ๋ผ์ ๊ธฐ๋ณธ์ ์ผ๋ก setState
๋ฅผ ํธ์ถํ๋ setFooHover
๊ตฌ์ฑ ์์์ ์ธ์คํด์ค ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ค๊ณ ํฉ๋๋ค. ์ฑ๋ฅ์์ ์ด์ ๋ก ๋ค์๊ณผ ๊ฐ์์ผ ํฉ๋๋ค.
// In Bar
setFooHover(fooHover) {
if (fooHover !== this.state.fooHover) {
this.setState({ fooHover });
}
}
์์์ undecorate
๋ผ๊ณ ๋ถ๋ฅด๋ ์ด์ ๋ react-dnd๊ฐ ๋ ๋์ ์ฐจ์์ ๊ตฌ์ฑ ์์๋ฅผ ์ฌ์ฉํ๊ณ ์ฐ๋ฆฌ๋ ํฌ์ฅ๋์ง ์์ ๊ตฌ์ฑ ์์๋ฅผ ์ํ๊ธฐ ๋๋ฌธ์
๋๋ค. ์ด๊ฒ์ ๋ด ์๊ฐ์ ๊ณ ์ฐจ ๊ตฌ์ฑ ์์์ ์ถ์
ํ ํฉ๋ณ์ฆ์
๋๋ค. ํ๋ญ์ค ์คํ ์ด๋ ๋ฌด์์ธ๊ฐ์ ์ก์
์ ๋ณด๋ด ๋์ ๊ตฌํํ ์๋ ์์ง๋ง, ์ ์ฒ๋ผ ํ๊ธฐ๋ก ๊ฒฐ์ ํ ๊ฒฝ์ฐ๋ฅผ ๋๋นํ์ฌ ์ฌ๊ธฐ undecorate
.
function undecorate(component) {
let curr = component;
while (typeof curr.getDecoratedComponentInstance === "function") {
curr = curr.getDecoratedComponentInstance();
}
return curr;
}
์ด์ ์ด๊ฒ์ ๊ตฌํํ๋ฉด ํ๋์ ์์ ๋ฌธ์ ๋ฅผ ์ ์ธํ๊ณ ๋ชจ๋ ๊ฒ์ด ์ข์ ๋ณด์ผ ๊ฒ์
๋๋ค. ์์
์ ์ ๋ ์ฌ๋ผ์ง์ง ์์ต๋๋ค! ์๋ฌด๋ setHoverState(null)
ํธ์ถํ์ง ์์ต๋๋ค(barTarget์ endHover ๊ธฐ๋ฅ๊ณผ ๊ฐ์ ๊ฒ์ ์์ต๋๋ค). ์ด๊ฒ์ ์ฒ๋ฆฌํ๋ ์ ์ ํ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ด componentWillReceiveProps
๊ฒ์
๋๋ค.
componentWillReceiveProps(nextProps) {
if (this.props.isFooOver && !nextProps.isFooOver) {
this.setState({ fooHover: null });
}
}
(์์ง ๊ธฐ๋ฅ์ { isFooOver: monitor.isOver() }
๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ์์ง ๋ง์ญ์์ค)
์ด๋ป๊ฒ ๋๋์ง ์๋ ค์ฃผ์ธ์!
์์ธํ ์ค๋ช ์ ๋ง ๊ฐ์ฌํฉ๋๋ค! ๋ด๊ฐ ์๋ ค ์ฃผ๋ง :)
๋ง์ง๋ง์ผ๋ก Redux ๋ฐฉ์์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ๊ธฐ๋ณธ์ ์ผ๋ก drop ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ์ ๋ ๋ฆฌ๋์๋ฅผ ํตํด ์ด๋ฒคํธ๋ฅผ ์ ๋ฌํ์ต๋๋ค.
drop: (propsTargetItem, monitor, targetItem) ->
draggedItem = monitor.getItem()# Item that has been dragged and eventually dropped.
coordsDrop = monitor.getClientOffset()# Coords of the drop action.
diff = monitor.getDifferenceFromInitialOffset()# Comparison of the initial click (dragging start) against the end of the click (dropping start).
patternId = draggedItem.patternId
patternPosition = draggedItem.position
targetId = propsTargetItem.context.patternId
targetPosition = propsTargetItem.context.position
isCursorAboveHalf = GeoService.isAboveHalf(ReactDOM.findDOMNode(targetItem), coordsDrop.y)
# Extract positions in the array of children.
oldPosition = draggedItem.position# Current position of the item, which will be the old position as soon as the item is moved. (by the server through sockets)
newPosition = calcDropPosition(targetId, patternId, patternPosition, targetPosition, isCursorAboveHalf)# Position where we will move the dragged item.
# Dispatch only if the position has changed and is set.
if oldPosition isnt newPosition and newPosition?
draggedItem.moveDnDPattern(Object.assign({}, draggedItem, {newPosition: newPosition, oldPosition: oldPosition}))
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
์ข์ต๋๋ค. ๋ฐ๋ผ์ ์์ด๋์ด๋ ๊ตฌ์ฑ ์์์์ ์ํ๋ฅผ ์ค์ ํ๊ณ ์ํ๊ฐ ์ค์ ๋๋ฉด ํด๋์ค๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ๋๋ค.
Foo๋ฅผ Bar๋ก ๋๋๊ทธํ๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค.
์ ์ผํ ์ง๋ฌธ์ ๊ทธ ์ํ๋ฅผ ์ด๋ป๊ฒ ์ค์ ํ๋๋๋ ๊ฒ์ ๋๋ค!
๋ฐ๋ผ์ ๊ธฐ๋ณธ์ ์ผ๋ก
setState
๋ฅผ ํธ์ถํ๋setFooHover
๊ตฌ์ฑ ์์์ ์ธ์คํด์ค ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ค๊ณ ํฉ๋๋ค. ์ฑ๋ฅ์์ ์ด์ ๋ก ๋ค์๊ณผ ๊ฐ์์ผ ํฉ๋๋ค.์์์
undecorate
๋ผ๊ณ ๋ถ๋ฅด๋ ์ด์ ๋ react-dnd๊ฐ ๋ ๋์ ์ฐจ์์ ๊ตฌ์ฑ ์์๋ฅผ ์ฌ์ฉํ๊ณ ์ฐ๋ฆฌ๋ ํฌ์ฅ๋์ง ์์ ๊ตฌ์ฑ ์์๋ฅผ ์ํ๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด๊ฒ์ ๋ด ์๊ฐ์ ๊ณ ์ฐจ ๊ตฌ์ฑ ์์์ ์ถ์ ํ ํฉ๋ณ์ฆ์ ๋๋ค. ํ๋ญ์ค ์คํ ์ด๋ ๋ฌด์์ธ๊ฐ์ ์ก์ ์ ๋ณด๋ด ๋์ ๊ตฌํํ ์๋ ์์ง๋ง, ์ ์ฒ๋ผ ํ๊ธฐ๋ก ๊ฒฐ์ ํ ๊ฒฝ์ฐ๋ฅผ ๋๋นํ์ฌ ์ฌ๊ธฐundecorate
.์ด์ ์ด๊ฒ์ ๊ตฌํํ๋ฉด ํ๋์ ์์ ๋ฌธ์ ๋ฅผ ์ ์ธํ๊ณ ๋ชจ๋ ๊ฒ์ด ์ข์ ๋ณด์ผ ๊ฒ์ ๋๋ค. ์์ ์ ์ ๋ ์ฌ๋ผ์ง์ง ์์ต๋๋ค! ์๋ฌด๋
setHoverState(null)
ํธ์ถํ์ง ์์ต๋๋ค(barTarget์ endHover ๊ธฐ๋ฅ๊ณผ ๊ฐ์ ๊ฒ์ ์์ต๋๋ค). ์ด๊ฒ์ ์ฒ๋ฆฌํ๋ ์ ์ ํ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ดcomponentWillReceiveProps
๊ฒ์ ๋๋ค.(์์ง ๊ธฐ๋ฅ์
{ isFooOver: monitor.isOver() }
๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ์์ง ๋ง์ญ์์ค)์ด๋ป๊ฒ ๋๋์ง ์๋ ค์ฃผ์ธ์!