๋์๊ฒ CustomDragLayer๊ฐ ๋์ ์ฑ๋ฅ์ ์ ๊ณตํ๋ ์ด์ ๊ฐ ์์ต๋๊น? ๋ฎ์ fps์ ๊ฐ๊ฑฐ๋ ์คํ๋ ค ๋ด๊ฐ ๋๊ณ ์๋ ์์์ ๊ฐ์ฒด๊ฐ ์ง์ฐ๋๊ณ ๋งค๋๋ฝ์ง ์๊ฒ ๋ณด์ ๋๋ค.
๋๋ ์ด๊ฒ์ ๊ฒฝํํ๋ค. ์ฌ๊ธฐ์ ๋ฌธ์ ๋ ๋๋๊ทธ ๋ ์ด์ด์์ ๋ณ๊ฒฝ๋์ง ์๋ ์์ ๊ตฌ์ฑ ์์๋ฅผ ๋ ๋๋งํ๋๋ผ๋ ์คํ์ ๋ณ๊ฒฝ์ผ๋ก ์ธํด ๋ชจ๋ ๋จ์ผ ๋ง์ฐ์ค ์ด๋์์ ์ต์ํ ๋ฐ์ ์กฐ์ ์ด ํธ๋ฆฌ๊ฑฐ๋๋ค๋ ๊ฒ์ ๋๋ค. ๋๋๊ทธ ๋ ์ด์ด๊ฐ ๋ณ๊ฒฝ๋์ง ์๋ ์ฌ์ฉ์ ์ ์ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์์๋ฅผ ํ์ํด์ผ ํ๋ ์ผ๋ฐ์ ์ธ ๊ฒฝ์ฐ์๋ ๋งค์ฐ ๋นํจ์จ์ ์ ๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด DragLayer.js
๊ฐ ์คํ์
๋ ๋๋ง์ ์ํํ๊ณ ๊ณ ์ฑ๋ฅ ๋ฐฉ์์ผ๋ก ๋ณต์ ํ์ต๋๋ค. ์ฆ, ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ฃผ์๋ฅผ ์ง์ ์ด๋ํ๋ ์ปจํ
์ด๋์ ์คํ์ผ์ ๋ณ๊ฒฝํ๋ ๊ฒ์
๋๋ค.
// PerformantDragLayer.js
/* eslint-disable */
import React, { Component, PropTypes } from 'react';
import shallowEqual from 'react-dnd/lib/utils/shallowEqual';
import shallowEqualScalar from 'react-dnd/lib/utils/shallowEqualScalar';
import isPlainObject from 'lodash/isPlainObject';
import invariant from 'invariant';
import checkDecoratorArguments from 'react-dnd/lib/utils/checkDecoratorArguments';
import hoistStatics from 'hoist-non-react-statics';
function layerStyles(isDragging) {
return {
position: 'fixed',
pointerEvents: 'none',
zIndex: 1,
left: 0,
top: 0,
width: isDragging ? '100%' : 0,
height: isDragging ? '100%' : 0,
opacity: isDragging ? 1 : 0
};
}
export default function DragLayer(collect, options = {}) {
checkDecoratorArguments('DragLayer', 'collect[, options]', ...arguments);
invariant(
typeof collect === 'function',
'Expected "collect" provided as the first argument to DragLayer ' +
'to be a function that collects props to inject into the component. ',
'Instead, received %s. ' +
'Read more: http://gaearon.github.io/react-dnd/docs-drag-layer.html',
collect
);
invariant(
isPlainObject(options),
'Expected "options" provided as the second argument to DragLayer to be ' +
'a plain object when specified. ' +
'Instead, received %s. ' +
'Read more: http://gaearon.github.io/react-dnd/docs-drag-layer.html',
options
);
return function decorateLayer(DecoratedComponent) {
const { arePropsEqual = shallowEqualScalar } = options;
const displayName =
DecoratedComponent.displayName ||
DecoratedComponent.name ||
'Component';
class DragLayerContainer extends Component {
static DecoratedComponent = DecoratedComponent;
static displayName = `DragLayer(${displayName})`;
static contextTypes = {
dragDropManager: PropTypes.object.isRequired
}
getDecoratedComponentInstance() {
return this.refs.child;
}
shouldComponentUpdate(nextProps, nextState) {
return !arePropsEqual(nextProps, this.props) ||
!shallowEqual(nextState, this.state);
}
constructor(props, context) {
super(props);
this.handleOffsetChange = this.handleOffsetChange.bind(this);
this.handleStateChange = this.handleStateChange.bind(this);
this.manager = context.dragDropManager;
invariant(
typeof this.manager === 'object',
'Could not find the drag and drop manager in the context of %s. ' +
'Make sure to wrap the top-level component of your app with DragDropContext. ' +
'Read more: http://gaearon.github.io/react-dnd/docs-troubleshooting.html#could-not-find-the-drag-and-drop-manager-in-the-context',
displayName,
displayName
);
this.state = this.getCurrentState();
}
componentDidMount() {
this.isCurrentlyMounted = true;
const monitor = this.manager.getMonitor();
this.unsubscribeFromOffsetChange = monitor.subscribeToOffsetChange(
this.handleOffsetChange
);
this.unsubscribeFromStateChange = monitor.subscribeToStateChange(
this.handleStateChange
);
this.handleStateChange();
}
componentWillUnmount() {
this.isCurrentlyMounted = false;
this.unsubscribeFromOffsetChange();
this.unsubscribeFromStateChange();
}
handleOffsetChange() {
if (!this.isCurrentlyMounted) {
return;
}
const monitor = this.manager.getMonitor();
const offset = monitor.getSourceClientOffset();
const offsetDiv = this.refs.offset;
if (offset && offsetDiv) {
offsetDiv.style.transform = `translate(${offset.x}px, ${offset.y}px)`;
}
}
handleStateChange() {
if (!this.isCurrentlyMounted) {
return;
}
const nextState = this.getCurrentState();
if (!shallowEqual(nextState, this.state)) {
this.setState(nextState);
}
}
getCurrentState() {
const monitor = this.manager.getMonitor();
return {
collected: collect(monitor),
isDragging: monitor.isDragging()
};
}
render() {
return (
<div style={layerStyles(this.state.isDragging)}>
<div ref='offset'>
{this.state.isDragging && <DecoratedComponent {...this.props} {...this.state.collected} ref='child' />}
</div>
</div>
);
}
}
return hoistStatics(DragLayerContainer, DecoratedComponent);
};
}
๊ทธ๋ฌ๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํ ์ ์์ต๋๋ค.
// MyCustomDragLayer.js
import PerformantDragLayer from './PerformantDragLayer'
import React, {PropTypes} from 'react'
class CustomDragLayerRaw extends React.Component {
static propTypes = {
item: PropTypes.any,
itemType: PropTypes.string
}
render () {
const {item, itemType} = this.props
return <div>{itemType}</div>
}
}
export default PerformantDragLayer((monitor) => ({
item: monitor.getItem(),
itemType: monitor.getItemType()
})(CustomDragLayerRaw)
์ฑ๋ฅ ํฅ์์ด ๋งค์ฐ ๋์ ๋๋๋ค.
๋ฌผ๋ก ๊ธฐ๋ณธ DragLayer
๊ฐ ๋ ์ ์ฐํฉ๋๋ค. ํน๋ณํ ๊ฒฝ์ฐ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ ๋ ์ฑ๋ฅ์ด ์ข์ ๊ตฌํ์ด ๋ ๋น ๋ฆ
๋๋ค. ํ์ง๋ง ์ด ํน๋ณํ ๊ฒฝ์ฐ๋ ๋งค์ฐ ํํ ์ผ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
@gaearon ๊ทธ๋ ๊ฒ ์ ๋ฌธํ๋์์ง๋ง ํจ์ฌ ๋ ์ฑ๋ฅ์ด ๋ฐ์ด๋ ๊ตฌํ์ด react-dnd์ ๋ํ ๋์์ผ๋ก ํตํฉ๋๋ ๋ฐ ํฅ๋ฏธ๊ฐ ์์ต๋๊น?
@choffmeister ์๋ ํ์ธ์. ๊ทํ์ ๊ฒ์๋ฌผ์ ๊ฐ์ฌ๋๋ฆฝ๋๋ค. ๋๋ ํ๋ฃจ ์ ์ ๊ทธ๊ฒ์ ๋ํด ๊ฐ๋ตํ๊ฒ ์ดํด๋ณด์์ง๋ง ๊ทธ๋์์ผ โโ๊น์ด ์ดํด๋ณด์์ต๋๋ค. ๊ฒ์ํ ์ฝ๋๋ ๊ตฌํ ๋ด์์ ๋งค์ฐ ์ ๋ฌธํ๋ ๊ฒ ๊ฐ์ต๋๋ค. ์ด์ ํ์ํ ์ค์ํ ์ธก๋ฉด์ ์ง์ ํด ์ฃผ์๊ฒ ์ต๋๊น? ๊ทธ๋ฆฌ๊ณ CustomDragLayerRaw๊ฐ ์ด๋ป๊ฒ ์ฌ์ฉ๋๋์ง๋ ๋งค์ฐ ์ ์ตํ ๊ฒ์ ๋๋ค.
๊ฐ์ง๊ณ ์๋ ๋ชจ๋ ํ๋ฌ๊ทธ์ธ, ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฐ ๊ธฐํ ์ฝ๋๊ฐ ์๋ฃจ์ ์ ์ผ๋ถ์ธ์ง ํ์คํ์ง ์์ต๋๋ค.
๊ฐ์ฌ ํด์
๋๋ ์ฃผ์๋ฅผ ์คํํ๊ณ ์๋ํ๋๋ก ๊ด๋ฆฌํ์ต๋๋ค. "๋๋๊ทธ ๊ณ ์คํธ"์ ์ํ๋ ์ฝํ ์ธ ๊ฐ '์คํ์ ' div์ ์์ด์ผ ํ๋ ๊ฒ ๊ฐ์ต๋๋ค. ์ด ์์ ์ ์ํํ๋ ์ต์ ์ ๋ฐฉ๋ฒ์ ๋ชจ๋ฅด์ง๋ง ๋ด ํ ์คํธ์์๋ ๋๋๊ทธํ ์ฝํ ์ธ ์ ๋น์ทํ div๋ฅผ ๋ฃ์์ต๋๋ค. ์์ง ๋๋๊ทธ ๋ ์ด์ด ํญ๋ชฉ์ ๋๋๊ทธ ํญ๋ชฉ๊ณผ ๋์ผํ๊ฒ ๋ง๋ค์ง ์์์ง๋ง ์ผ๋ถ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๊ณ ๋๋๊ทธ ๋ ์ด์ด ํญ๋ชฉ์ ์ํ๋ฅผ ๋ณ๊ฒฝํ๋ ๊ฒ์ ๊ทธ๋ฆฌ ์ด๋ ต์ง ์์ต๋๋ค.
์ฑ๋ฅ์ ๋งค์ฐ ์ข์ง๋ง ์ปจํ ์ด๋ ์ธ๋ถ๋ก ๋ ๋๋ง ์๋ํฉ๋๋ค. ํญ๋ชฉ ์ฃผ์๋ฅผ ์์ผ๋ก ๋๋๊ทธํ๋ฉด ์ฑ๋ฅ๋ ์ด์ ์ ๊ฒฝ์ฐ์ ๋ง์ฐฌ๊ฐ์ง๋ก ์๋ฒฝํฉ๋๋ค(์ฆ, 4๊ฐ์ ํญ๋ชฉ ๋ชฉ๋ก์ด ์๊ณ 4๋ฒ์งธ ํญ๋ชฉ ์์ญ์์ ๋ง์ฐ์ค๋ฅผ ๋๋๊ทธํ ์ํ๋ก ์ ์ง). ๊ทธ๋ฌ๋ 4๊ฐ ์์ ๋ชจ๋์ ๊ฑธ์ณ ๋ง์ฐ์ค๋ก ์์ ๊ทธ๋ฆฌ๊ณ ๋๋๊ทธํ๋ฉด ์ด์ ๊ณผ ๊ฐ์ด ์ฌ์ ํ ์ง์ฐ๋์ง๋ง ์ฝ๊ฐ์ fps ๊ฐ์ ์ด ์์ต๋๋ค(๊ทธ๋๋ ์ฌ์ ํ ์ง์ฐ๋จ). ๊ทธ๋ฌ๋ ์ด ๊ตฌํ์ ์ข์ ์์์ ๋๋ค. ์ ์ด๋ ํ ์ปจํ ์ด๋์์ ๋ค๋ฅธ ์ปจํ ์ด๋๋ก ๋๋๊ทธํ๋ ค๋ ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ๊ฒฝ์ฐ์๋ UX๋ฅผ ํ์คํ ์ ์งํฉ๋๋ค.
์ง์ฐ์ด ์ ํํ ๋ฌด์์ ์๋ฏธํฉ๋๊น?
๋๋ ๋ ๋ค ๋งํ ๊ฒ์ด๋ค
๋ ์ฌ์ฉํ๋ฉด์ ์๋ฃจ์ ์ด ์ค์ ๋ก ์ง์ฐ์ ์์ ํ ์ ๊ฑฐํ์ง ๋ชปํ๋ค๋ ๊ฒ์ ๊นจ๋ฌ์์ต๋๋ค. ๋๋ ๊ทธ๊ฒ์ ์กฐ์ฉํ ์ฝ๊ฐ์ ๊ธฐ๋ฅ์ด ์๋ ์นด๋ div๊ฐ ์์ต๋๋ค. ๊ทํ์ ์๋ฃจ์ ์ ์ฒ์์ ๋ฌธ์์ ์์ ๋น๊ตํ์ฌ ์์ฒญ๋ fps ํฅ์์ ์ ๊ณตํ์ง๋ง ๋ด div๋ฅผ ๋ ๋ณต์กํ๊ฒ ๋ง๋ค๋ฉด ์ด๊ฒ์ด ์๋ ๊ฒ์ฒ๋ผ ์ง์ฐ๋๊ธฐ ์์ํฉ๋๋ค.
์๋ฏธ๋ก ์ UI๊ฐ ์ด ๋ฌธ์ ๋ฅผ ์ผ์ผํค๊ฑฐ๋ dnd์ ๋ฐ์ํ๋์ง ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. ๋๋๊ทธ ๋ ์ด์ด์ ์ฑ๋ฅ์ ๋์ด๋ ๋ค๋ฅธ ์ต์ ์ ๋ฐฉ๋ฒ์ด ์๋ค๋ฉด ์ ๋ง ์๊ณ ์ถ์ต๋๋ค.
๋ํ ๋๊ตฐ๊ฐ๊ฐ ์์ ์๊ฒ ๋ค๋จ์ด์ง๋์ง ํ์ธํ๊ณ ์ถ๋ค๋ฉด ๋ด๋ถ์ ๋ง์ ์์๊ฐ ํฌํจ๋ Semantic UI ์นด๋๋ฅผ ์ฌ์ฉํ์ต๋๋ค. ๋ด ์๋ฆฌ ํ์์ ์นด๋์๋ 2๊ฐ์ ์ ๋ชฉ, 5๊ฐ์ ์๋ฏธ๋ก ์ "๋ ์ด๋ธ", 3๊ฐ์ ์๋ฏธ๋ก ์ "์์ด์ฝ" ๋ฐ ์๋ฐํ ์ด๋ฏธ์ง๊ฐ ์์ต๋๋ค.
http://react-trello-board.web-pal.com/ ์์ ์ด ๋ค๋ฅธ ์๋ฅผ ์ถ๊ฐ๋ก ํ ์คํธํ ํ(๊ตฌํ์ choffmeister๊ฐ ์ด์ ์ ๊ฒ์ํ ๊ฒ๊ณผ ๋งค์ฐ ์ ์ฌํจ) ๋ณต์กํ div๋ฅผ ๋๋๊ทธํ๋ ค๊ณ ํ ๋ ์ฌ์ ํ ์ง์ฐ์ด ๋ฐ์ํฉ๋๋ค. . ์ฝ๋๋ฅผ ๋ ์คํํ ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ด ๋ด๊ฐ ๋ด๋ฆฐ ๊ฒฐ๋ก ์ด๋ผ ๊ธฐ์ฉ๋๋ค. ๋ฌธ์ ๋ ์ฝ๊ฒ ๊ณ ์น ์ ์๋ ๋ด div์ ์์ต๋๋ค.
๋๋ ์ฌ์ ํ ๋ฌธ์์ ์์ ์ ๋งค์ฐ ์ ์ฌํ ์ฝ๋๋ฅผ ์ฌ์ฉํ์ฌ ์ด๊ฒ์ ๊ฝค ์ฌํ๊ฒ ๊ฒฝํํ๊ณ ์์ต๋๋ค. ์์ ๋ง์ฐ์ค๊ฐ ์์ง์ผ ๋๋ง๋ค ๋ณํ ๊ณ์ฐ์ ํด์ผ ํฉ๋๊น?
๋ค๋ฅธ ์ฌ๋์ด ์ด์ ๋ํ ํด๊ฒฐ์ฑ ์ ์ฐพ์์ต๋๊น?
PureComponents์์๋ ์ฑ๋ฅ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค. Chrome React Dev ํ๋ฌ๊ทธ์ธ์ '์
๋ฐ์ดํธ ๊ฐ์กฐ' ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ฌ ์ง๋จํ๋ฉด currentOffset
์ํ์ด ๋ณ๊ฒฝ๋ ๋ ๋ชจ๋ ๊ตฌ์ฑ ์์๊ฐ ์
๋ฐ์ดํธ๋ ๊ฒ์ฒ๋ผ ๋ณด์
๋๋ค. ์ด๋ฅผ ์ํํ๊ธฐ ์ํด ์ฑ์ ์ต์์ ์์ค์ ์ด๋ค ํญ๋ชฉ์ด ๋๋๊ทธ๋๋์ง ์ถ์ ํ๊ธฐ ์ํ DragLayer๊ฐ ์ด๋ฏธ ์๋๋ผ๋ ์ด ์ํ์ ์ ๋ฌํ๋ DragLayer์ ๋๋๊ทธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์์ฒด๋ง ํฌํจ๋๋๋ก ํ์ต๋๋ค.
@choffmeister ์ ์๋ฃจ์ ์ ์ ์ฉํ๋ ค๊ณ ์๋ํ์ง๋ ์์์ง๋ง ๋ฌธ์ ๋ ํด๊ฒฐํ ์ ์์ ๊ฒ ๊ฐ์ต๋๋ค. ๋๋ ์ด๊ฒ์ด ๋๋๊ทธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ฅผ ๊ตฌํํ๋ ๋ชจ๋ ์ฌ๋์๊ฒ ๊ณตํต์ ์ธ ๋ฌธ์ ๋ผ๊ณ ์์ํ ์ ์๊ธฐ ๋๋ฌธ์ ์ฝ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ํด ์ด์ ๊ฐ์ ๊ฒ์ ๊ณ ๋ คํด์ผ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
์ด ์ํ์ ์ ๋ฌํ๋ DragLayer์๋ ์ฑ์ ์ต์์ ์์ค์ ์ด๋ฏธ DragLayer๊ฐ ์์์๋ ๋ถ๊ตฌํ๊ณ ๋๋๊ทธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์์ฒด๋ง ํฌํจ๋์ด ์๋์ง ํ์ธํ์ต๋๋ค.
ํ๋ก์ฐ ํ๊ณ ์๋์ง ๋ชจ๋ฅด๊ฒ ๋ค์! ๋ด ์ฑ์๋ ์ฌ์ฉ์ ์ ์ ๋๋๊ทธ ๋ ์ด์ด๊ฐ ํ๋๋ง ์์ต๋๋ค.
๋ด ์ฌ์ฉ ์ฌ๋ก์๋ง ํด๋นํ๋ ๋ฌธ์ ์ ๋๋ค. ๋๋๊ทธ ์ค์ธ ํญ๋ชฉ์ ์ถ์ ํ๊ธฐ ์ํด ์ฌ์ฉ์ ์ง์ ๋๋๊ทธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๊ฐ ํ์ํ๊ธฐ ์ ์ ๋๋๊ทธ ๋ ์ด์ด๊ฐ ์ด๋ฏธ ์ฌ์ฉ ์ค์ด์์ต๋๋ค. ์ฒ์์๋ ์ถ๊ฐํ ๋ ์ฌ์ฉ์ ์ง์ ๋๋๊ทธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ฅผ ์ํํ๊ธฐ ์ํด ๋์ผํ ๋๋๊ทธ ๋ ์ด์ด๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ํฉ๋ฆฌ์ ์ด๋ผ๊ณ ์๊ฐํ์ง๋ง ์ด๊ฒ์ด ๋ด ์์ฉ ํ๋ก๊ทธ๋จ์ ์ต์์ ์์ค์ ์์๊ธฐ ๋๋ฌธ์ ์ฝ๊ฐ์ ์์ง์ผ ๋๋ง๋ค ์ด์ ๋ํ ์ํ์ ๋ณ๊ฒฝํ๋ฉด ๋ง์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค. ์ถ๊ฐ ๊ตฌ์ฑ ์์ ์ ๋ฐ์ดํธ.
๊ฐ์ฌํฉ๋๋ค.
๋๋๊ทธ ๋ ์ด์ด๋ฅผ ๋จ์ผ ๋ฒ์ด๋ฆฌ ๊ตฌ์ฑ ์์๋ก ๋จ์ํํ์ต๋๋ค. ๋ด๊ฐ ๋งํ ์์๋ ํ ์ง์ฐ์ ์ผ์ผํค๋ ๊ฒ์ ์ผ์ ํ x/y ๊ณ์ฐ์ ๋๋ค.
๋๋ ์์ง ์์์ @choffmeister ๊ฐ ํ๋ ์ผ์ ์ ๋ฐ๋ฅด์ง ์์ง๋ง ๋ ์์ธํ ์ดํด๋ด์ผ ํ ๊ฒ ๊ฐ์ต๋๋ค.
@gaearon ์ด๊ฒ์ lib์ ๋ํด ๊ฝค ๊ด์ฐฎ์ ๋ฌธ์ ์ธ ๊ฒ ๊ฐ์ต๋๋ค. ์ ์ ํ ์์ ์ฌํญ์ ๋ํ ์ ์ ์ฌํญ์ด ์์ต๋๊น?
react-dnd-html5-backend๋ ์ฌ์ฉ์ ์ ์ DragLayer์์ ์ฑ๋ฅ์ด ์ข์ง ์์ ๋ฐ๋ฉด react-dnd-touch-backend๋ ์ฑ๋ฅ์ด ์ํธํ ๊ฒ ๊ฐ์ต๋๋ค.
๋ปํ์ง๋ง ๋์์ด ๋ฉ๋๋ค.
let updates = 0;
@DragLayer(monitor => {
if (updates++ % 2 === 0) {
return {
currentOffset: monitor.getSourceClientOffset()
}
}
else {
return {}
}
})
๋ ๋ค๋ฅธ ํด๊ฒฐ ๋ฐฉ๋ฒ์ react-throttle-render
ํจํค์ง๋ฅผ ์ฌ์ฉํ์ฌ DragLayer์ ๋ ๋๋ง ๋ฐฉ๋ฒ์ ์กฐ์ ํ๋ ๊ฒ์
๋๋ค.
@aks427 ๊ฐ์ฌํฉ๋๋ค. ์๋ํด ๋ณด๊ณ ๋ ๊ฐ์ ๋๋์ง ํ์ธํ๊ฒ ์ต๋๋ค(์์ ๊ฐ์ ์ฌ์ฉ์ ์ง์ ๋๋๊ทธ ๋ ์ด์ด๋ฅผ ์ฌ์ฉํ์ฌ ๋๋ถ๋ถ์ ๊ฒฝ์ฐ์ ๋ง์ ๋์์ด ๋์์ง๋ง ์ ๋ถ๋ ์๋)
@dobesv ๋ฅผ react-dnd-touch-backend๋ก ๋ณ๊ฒฝํ๋ฉด ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋์์ต๋๋ค. ๋๋ ๋ํ react-throttle-render๋ฅผ ์๋ํ์ง๋ง ์ฌ์ ํ ์ข์ง ์์ ๊ฒ ๊ฐ์ต๋๋ค.
์, ํฐ์น ๋ฐฑ์๋๊ฐ ์๋ํ๋ค๋ ๊ฒ์ ์๊ณ ์์ง๋ง ์ฌ์ฉํ๋ ค๋ ๋์ด์ ๋๊ธฐ ํ์ผ ์ ๋ก๋๋ฅผ ์ง์ํ์ง ์์ต๋๋ค.
@dobesv ์ฐ๋ฆฌ๋ ๋๋๊ทธ ์ค ๋๋กญ ํ์ผ์ https://react-dropzone.js.org/๋ฅผ ์ฌ์ฉํฉ๋๋ค. :) ์๋ง๋ ๋น์ ์๊ฒ๋ ์ข์ ๊ฒ์ ๋๋ค.
@dobesv ๋ ๋ด ์๊ฒฌ์ ๋ฌด์ํฉ๋๋ค. react-dropzone์ ๋๋กญ ํ์ผ๋ง ์ง์ํฉ๋๋ค.
๊ทธ๋ฌ๋ ๋ณด๋ค ์ผ๋ฐ์ ์ธ ์๋๋ฆฌ์ค์ ๊ฒฝ์ฐ ํ์ผ์ ์ ๋ก๋ํด์ผ ํ๋ ๊ฒฝ์ฐ ํ์ผ์ด ๋ธ๋ผ์ฐ์ ์ธ๋ถ์ ์์ด์ผ ํฉ๋๋ค. ๋๋กญ ํ์ผ๋ง ์์ผ๋ฉด ๋ฉ๋๋ค.
๋ณ๊ฑฐ ์๋ ๊ฒ ๊ฐ์ง๋ง ์ฑ๋ฅ์ด ์ข์ ๋๋๊ทธ ๋ ์ด์ด ์์ ์ ์ฌ์ฉํ๊ณ
๋ ๋๋ง ์๋ฅผ ์ ํํ๊ธฐ ์ํด ๋ด ์ฝ๋๋ฅผ ๋ณด๋ ๋ฐ ๋ง์ ์๊ฐ์ด
์ฑ์ ์ํด ํธ์ถ๋๊ณ (์ปดํฌ๋ํธ -> PureComponent ์ ํ์ด ๋ง์)
๊ฒฐ๊ตญ ๋๋ react-throttle-render๋ฅผ ์ฌ์ฉํ ํ์์กฐ์ฐจ ์์์ต๋๋ค.
PureComponent๋ฅผ ์ฌ์ฉํ๊ณ ๋ค์์ ์๋ํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
์ด ์ค๋ ๋์์ ์ฌ์ด ์์ ์ ์ฐพ๋ ๋์ ์ฝ๋๋ฅผ ์ต๋ํํ์ญ์์ค.
๋ ๋๋ง์ด ๋๋ฆฝ๋๋ค! ๋ค์์์ ์ฑ๋ฅ ๋ชจ๋ธ์ ๊ฐ์ ํ๋ฉด ๋ ๋ง์ ๋ด์ฉ์ ๊ฒ์ํ๊ฒ ์ต๋๋ค.
๊ทธ๋๋!
>
@framerate PureComponents ๋ฅผ ์ฌ์ฉํ๋๋ผ๋ ์กฐ์ ์๊ณ ๋ฆฌ์ฆ์ ๋ง์ฐ์ค๋ฅผ ์์ง์ผ ๋๋ง๋ค ์คํํ๋ ๋ฐ ๋น์ฉ์ด ๋ง์ด ๋ค๊ธฐ ๋๋ฌธ์ ๋ฌธ์ ์ ๋๋ค. Chrome DevTools๋ฅผ ์ฌ์ฉํ์ฌ ur ์ฑ์ ํ๋กํ์ผ๋งํ๊ณ CPU๋ฅผ 4X๋ก ์กฐ์ ํ๋ฉด ๋ฏธ๋์๋ ๋ชจ๋ฐ์ผ ์ฅ์น์ ๊ฒฝ์ฐ ์ค์ ์๋๊ฐ ๋๋ ค์ง๋๋ค.
ํ์๊ณผ ๋๋๊ทธ ์ฑ๋ฅ์ ์ด๋ ค์์ ๊ฒช๊ณ ์๊ณ @choffmeister ์๋ฃจ์ ์์์ ๊ฐ์ด ๋ง์ ์ฝ๋๋ฅผ ๊ฐ์ ธ์ค๊ณ ์ถ์ง ์์ ์ฌ๋์ ์ํด:
let subscribedToOffsetChange = false;
let dragPreviewRef = null;
const onOffsetChange = monitor => () => {
if (!dragPreviewRef) return;
const offset = monitor.getSourceClientOffset();
if (!offset) return;
const transform = `translate(${offset.x}px, ${offset.y}px)`;
dragPreviewRef.style["transform"] = transform;
dragPreviewRef.style["-webkit-transform"] = transform;
};
export default DragLayer(monitor => {
if (!subscribedToOffsetChange) {
monitor.subscribeToOffsetChange(onOffsetChange(monitor));
subscribedToOffsetChange = true;
}
return {
itemBeingDragged: monitor.getItem(),
componentType: monitor.getItemType(),
beingDragged: monitor.isDragging()
};
})(
class CustomDragLayer extends React.PureComponent {
componentDidUpdate(prevProps) {
dragPreviewRef = this.rootNode;
}
render() {
if (!this.props.beingDragged) return null;
return (
<div
role="presentation"
ref={el => (this.rootNode = el)}
style={{
position: "fixed",
pointerEvents: "none",
top: 0,
left: 0
}}
>
{renderComponent(
this.props.componentType,
this.props.itemBeingDragged
)}
</div>
);
}
}
);
@stellarhoof ์ข์ ๋ต๋ณ ๊ฐ์ฌํฉ๋๋ค! ๋ถํํ๋ ์๋ฃจ์
์ IE11์์ ์๋ํ์ง ์์ต๋๋ค. subscribeToOffsetChange
๋ ์ฐ๋ฆฌ๊ฐ ์ ๋ฌํ ์ฝ๋ฐฑ์ ํธ์ถํ์ง ์๋ ๊ฒ ๊ฐ์ต๋๋ค. ๋คํํ subscribeToOffsetChange
๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋์ ๋ค์๊ณผ ๊ฐ์ด ์์ง๊ธฐ ๋ด๋ถ์ ๋ฒ์ญ์ ์ค์ ํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์์ต๋๋ค.
let dragLayerRef: HTMLElement = null;
const layerStyles: React.CSSProperties = {
position: 'fixed',
pointerEvents: 'none',
zIndex: 100,
left: 0,
top: 0,
width: '100%',
height: '100%',
};
const dragLayerCollector = (monitor: DragLayerMonitor) => {
if (dragLayerRef) {
const offset = monitor.getSourceClientOffset() || monitor.getInitialClientOffset();
if (offset) {
dragLayerRef.style["transform"] = `translate(${offset.x}px, ${offset.y}px)`;
} else {
dragLayerRef.style["display"] = `none`;
}
}
return {
item: monitor.getItem(),
isDragging: monitor.isDragging(),
};
};
export default DragLayer(dragLayerCollector)(
(props): JSX.Element => {
if (!props.isDragging) {
return null;
}
return (
<div style={layerStyles}>
<div ref={ (ref) => dragLayerRef = ref }>test</div>
</div>
);
}
);
@stellarhoof renderComponent
์ด ์ ์๋์ง ์์ ๊ฒ์ ์์์ต๋๋ค. ๋ ํฐ ํ์ผ์ ์ผ๋ถ์์ต๋๊น? (React๋ ๊ฐ์ ธ์ค์ง ์์)
@choffmeister dnd์ ์ดํ ๋ฒ์ ์ผ๋ก ์ ๋ฐ์ดํธํ์ จ์ต๋๊น? ์ปจํ ์คํธ ๋ณ๊ฒฝ์ผ๋ก ์ธํด ๊ตฌํ์ด ์ค๋จ๋ ๊ฒ์ผ๋ก ๋ณด์ด๋ฉฐ ์ด๋ฅผ ์๋ํ๊ณ @stellarhoof ๊ฐ ์ํํ ์์ ๊ณผ ๋น๊ตํ๊ณ ์ถ์์ต๋๋ค.
@stellarhoof ์ข์ ๋ต๋ณ ๊ฐ์ฌํฉ๋๋ค! ๋ถํํ๋ ์๋ฃจ์ ์ IE11์์ ์๋ํ์ง ์์ต๋๋ค.
subscribeToOffsetChange
๋ ์ฐ๋ฆฌ๊ฐ ์ ๋ฌํ ์ฝ๋ฐฑ์ ํธ์ถํ์ง ์๋ ๊ฒ ๊ฐ์ต๋๋ค. ๋คํํsubscribeToOffsetChange
๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋์ ๋ค์๊ณผ ๊ฐ์ด ์์ง๊ธฐ ๋ด๋ถ์ ๋ฒ์ญ์ ์ค์ ํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์์ต๋๋ค.let dragLayerRef: HTMLElement = null; const layerStyles: React.CSSProperties = { position: 'fixed', pointerEvents: 'none', zIndex: 100, left: 0, top: 0, width: '100%', height: '100%', }; const dragLayerCollector = (monitor: DragLayerMonitor) => { if (dragLayerRef) { const offset = monitor.getSourceClientOffset() || monitor.getInitialClientOffset(); if (offset) { dragLayerRef.style["transform"] = `translate(${offset.x}px, ${offset.y}px)`; } else { dragLayerRef.style["display"] = `none`; } } return { item: monitor.getItem(), isDragging: monitor.isDragging(), }; }; export default DragLayer(dragLayerCollector)( (props): JSX.Element => { if (!props.isDragging) { return null; } return ( <div style={layerStyles}> <div ref={ (ref) => dragLayerRef = ref }>test</div> </div> ); } );
์ด๊ฒ์ ๋๋ฅผ ์ํด ์ผํ์ต๋๋ค!
์ด ๋ฒ์ ์ ์ฌ์ฉํ๊ณ ์์ต๋๋ค: 9.4.0
๋ค๋ฅธ ์๋ฃจ์ ์ ์ด์ ๋ฒ์ ์์๋ง ์๋ํ๋ ๊ฒ ๊ฐ์ต๋๋ค.
์๋ค ์,
๊ณ์ ์งํํ๊ธฐ ์ ์ CSS ์ ๋๋ฉ์ด์ ๊ตฌ์ฑ ์์๋ฅผ ๋๋๊ทธ ๊ฐ๋ฅํ๊ฒ ๋ง๋ค๊ฑฐ๋ ์ต์ํ transition ์์ฑ์ ์ ๊ฑฐํ์ง ๋ง์ญ์์ค.
์ ํ ์์ฑ onStart๋ฅผ ์ ๊ฑฐํ๊ณ ๋ค์ onEnd์ ์ถ๊ฐํ ํ ๋ชจ๋ ๊ฒ์ด ์ ๋๋ก ์๋ํ์ต๋๋ค.
ํํฌ(useDragLayer ํํฌ)๋ฅผ ์ฌ์ฉํ๊ณ ์ฌ๊ธฐ์ ์ฐฉ๋ฅํ๋ ์ฌ๋๋ค์ ์ํด: ์ ๋ ํนํ ํํฌ ๊ตฌํ์ ๋ํ ํฐ์ผ์ ์ด์์ผ๋ฉฐ ์ฌ๊ธฐ์ ํด๊ฒฐ ๋ฐฉ๋ฒ ์ ์์ด ์์ต๋๋ค: https://github.com/react-dnd/react-dnd/issues/2414
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
react-dnd-html5-backend๋ ์ฌ์ฉ์ ์ ์ DragLayer์์ ์ฑ๋ฅ์ด ์ข์ง ์์ ๋ฐ๋ฉด react-dnd-touch-backend๋ ์ฑ๋ฅ์ด ์ํธํ ๊ฒ ๊ฐ์ต๋๋ค.