React-dnd: "๋“œ๋กญ ํ›„ ํ˜ธ๋ฒ„๋ฅผ ํ˜ธ์ถœ ํ•  ์ˆ˜ ์—†์Œ"์„ ๋””๋ฒ„๊น…ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

์— ๋งŒ๋“  2016๋…„ 04์›” 19์ผ  ยท  24์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: react-dnd/react-dnd

์•ˆ๋…•ํ•˜์„ธ์š”,
๋‚ด ๋™๋ฃŒ ์ค‘ ํ•œ ๋ช…์ด ์–ด๋–ป๊ฒŒ ๋“  ๋ชจ๋‹ˆํ„ฐ ์ƒํƒœ๋ฅผ ๊นจ๋œจ๋ฆด ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋งˆ์šฐ์Šค๊ฐ€ ์˜ฌ๋ผ์™€ ์žˆ์–ด๋„ ๋งˆ์šฐ์Šค๊ฐ€ ๋– ์žˆ๋Š” ๊ฒƒ์œผ๋กœ ์ƒ๊ฐํ•˜๊ณ  ๋‹ค์Œ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

screenshot 2016-04-19 16 34 56

๋””๋ฒ„๊น…์„ ์‹œ์ž‘ํ•  ์œ„์น˜์— ๋Œ€ํ•œ ์•„์ด๋””์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ์žฌํ˜„ ํ•  ์ˆ˜ ์—†์œผ๋ฉฐ ๊ทธ๋Š” ์ผ์ฃผ์ผ์— ํ•œ ๋ฒˆ ๊ทธ๊ฒƒ์„ ๋ณธ๋‹ค.
๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์ „ํ™˜ ๋œ ํ„ฐ์น˜ ๋ฐฑ์—”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

triage wontfix

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

์ด ๋ฌธ์ œ๋„ ๋ฐœ์ƒํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ œ ์ƒํ™ฉ์€ React ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋“œ๋กญ ๋Œ€์ƒ์ด์ž ๋“œ๋ž˜๊ทธ ์†Œ์Šค ์ธ ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‘ ๊ฐœ์˜ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€์žˆ์„ ๋•Œ ์œ„์˜ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์ „์— ํ•œ ๋ฒˆ ๋Œ์–ด์„œ ๋†“์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์„ธ ๊ฐœ ์žˆ์œผ๋ฉด ์˜ค๋ฅ˜์—†์ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๋‹จ์ผ ๊ตฌ์„ฑ ์š”์†Œ์˜ ์—ฌ๋Ÿฌ ์ปจํ…์ŠคํŠธ์™€ ๊ด€๋ จ์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๊นŒ?

๋ชจ๋“  24 ๋Œ“๊ธ€

๊ทธ๋ž˜์„œ JS ๋ฌธ์ œ๋ฅผ ์กฐ์‚ฌํ•œ ๊ฒฐ๊ณผ์ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์ „์— ๋“œ๋กญ์ด ๋ฐœ์ƒํ•  ๋•Œ ์‚ฌ์šฉ์ž ์ •์˜ ์ฝœ๋ฐฑ์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ๋ชจ๋‹ˆํ„ฐ / ์Šคํ† ์–ด์˜ ์ƒํƒœ๊ฐ€ ์†์ƒ ๋  ์ˆ˜ ์žˆ์Œ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋„ ๋ฐœ์ƒํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ œ ์ƒํ™ฉ์€ React ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋“œ๋กญ ๋Œ€์ƒ์ด์ž ๋“œ๋ž˜๊ทธ ์†Œ์Šค ์ธ ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‘ ๊ฐœ์˜ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€์žˆ์„ ๋•Œ ์œ„์˜ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์ „์— ํ•œ ๋ฒˆ ๋Œ์–ด์„œ ๋†“์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์„ธ ๊ฐœ ์žˆ์œผ๋ฉด ์˜ค๋ฅ˜์—†์ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๋‹จ์ผ ๊ตฌ์„ฑ ์š”์†Œ์˜ ์—ฌ๋Ÿฌ ์ปจํ…์ŠคํŠธ์™€ ๊ด€๋ จ์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๊นŒ?

์ด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ์ง€๋‚œ ๋ฐค ํŠน์ • ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋Œ€ํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค.

์ปจํ…์ŠคํŠธ๋ฅผ ์œ„ํ•ด DragSources ๋ชฉ๋ก์„ ๋ Œ๋”๋งํ•˜๊ณ  ์žˆ์—ˆ๊ณ  DropTarget์— ๋“œ๋กญ ๋œ ํ•ญ๋ชฉ์ด ์žˆ์œผ๋ฉด DragSources ๋ชฉ๋ก์—์„œ ์ œ๊ฑฐ๋˜๊ณ  DropTarget์€ DragSource์˜ ์ฝ˜ํ…์ธ ๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ๋กœ ๋Œ€์ฒด๋ฉ๋‹ˆ๋‹ค.

์ด ๋Œ์–ด์„œ ๋†“๊ธฐ ๊ธฐ๋Šฅ (ํ•ญ๋ชฉ์— '๋ฒ”์ฃผ'๋ฅผ ์ผ์น˜์‹œํ‚ค๋Š” ๊ตฌ์„ฑ ์š”์†Œ)์˜ ํ•„์ˆ˜ ๋ถ€๋ถ„์€ ํ•ญ๋ชฉ์„ DragSource ๋ชฉ๋ก์— ๋‹ค์‹œ ์ถ”๊ฐ€ํ•˜๋Š” ๊ธฐ๋Šฅ์œผ๋กœ, ๋ฐฐ์น˜ ๋œ ํ•ญ๋ชฉ์„ DragSource๋กœ ๋ฐ”๊พธ๊ณ  DragSources์— ๋‹ค์‹œ ์ถ”๊ฐ€ํ•˜๊ธฐ ๋งŒํ•˜๋ฉด๋ฉ๋‹ˆ๋‹ค. ๋ช…๋ถ€.

image

์ด์ œ์ด ์˜ˆ์™ธ๋Š” ๋ชจ๋“  ๋ฒ”์ฃผ์— ํ•ญ๋ชฉ์„ ๋ฐฐ์น˜ํ•˜๊ณ  ์ ์–ด๋„ ํ•˜๋‚˜๋ฅผ ์ œ๊ฑฐ ํ•  ๋•Œ๋งŒ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค (๋ชฉ๋ก์ด ๊ฐ€๋“ ์ฐจ์ง€ ์•Š์•˜๊ณ  ํ•˜๋‚˜๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ๋‹ค์‹œ ์ถ”๊ฐ€ ํ•  ๋•Œ๊ฐ€ ์•„๋‹˜). ๊ทธ๋ž˜์„œ ์ €๋Š” DragSources ๋ชฉ๋ก์— ์ด๊ฒƒ์ด ๋ฐœ์ƒํ•˜๋Š” ์ž์‹์ด ์ „ํ˜€ ์—†์„ ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒฐ๋ก ์— ๋„๋‹ฌํ–ˆ์Šต๋‹ˆ๋‹ค (์•„๋งˆ๋„ ์ปจํ…Œ์ด๋„ˆ ์š”์†Œ๊ฐ€ ์‚ฌ๋ผ์ง€๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ํ…Œ์ŠคํŠธ ํ•  ์‹œ๊ฐ„์ด ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค). ์ด๋ฅผ ์™„ํ™”ํ•˜๊ธฐ ์œ„ํ•ด ๋ฐฐ์น˜์‹œ DragSources ๋ชฉ๋ก์—์„œ ํ•ญ๋ชฉ์„ ์ œ๊ฑฐํ•˜๋Š” ๋Œ€์‹  ํ•ด๋‹น ์Šคํƒ€์ผ์„ display: none

์„ค๋ช…ํ•˜๊ธฐ ์–ด๋ ต์ง€๋งŒ ๋„์›€์ด ๋˜์—ˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

@PendragonDevelopment์™€ ๋™์ผํ•œ ํšจ๊ณผ๋ฅผ ๊ฒฝํ—˜ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ๋ชฉ๋ก์€ ํ•˜๋‚˜์˜ ํ•ญ๋ชฉ์œผ๋กœ ์‹œ์ž‘ํ•˜์—ฌ ๋‘ ๋ฒˆ์งธ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ ํ•œ ๋‹ค์Œ ๋‹ค์‹œ ์ •๋ ฌ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Javascript ์˜ค๋ฅ˜๊ฐ€ ํ‘œ์‹œ๋˜๊ธฐ ์ „์— ๋‘ ํ•ญ๋ชฉ์„ ํ•œ ๋ฒˆ๋งŒ ์žฌ์ •๋ ฌ ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋‹ค์‹œ ์ •๋ ฌ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋‚˜๋„์ด ๋ฌธ์ œ๊ฐ€์žˆ๋‹ค
์ด์œ ๋Š” ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ ์ฒซ ๋ฒˆ์งธ ์žฌ๋ฐฐ์น˜ ํ›„ ์ด๋Ÿฌํ•œ ์˜ค๋ฅ˜๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—๋„ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ๋ชจ ์˜ˆ์ œ์™€ ๋‚ด ๊ฒƒ์„ ๋น„๊ต ํ•œ ํ›„ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋ฃจํ”„ ํ•  ๋•Œ ๋ฐฐ์—ด ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ํ‚ค ์™€ ์ธ๋ฑ์Šค ๋ชจ๋‘ ์„ค์ •ํ•˜๊ณ  ๋ฐ๋ชจ์—์„œ๋Š” Sortable / Simple / Container.js ์ธ๋ฑ์Šค ๋งŒ ์„ค์ •ํ•˜๊ณ  ํ‚ค ๊ฐ€ ๊ณ ์ •๋˜์–ด ์žˆ์Œ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ•ด๋ƒˆ๊ณ  ์ผํ–ˆ์Šต๋‹ˆ๋‹ค!

ํ‚ค๋Š” ๊ณ ์ • ๊ฐ’์ด์–ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๊ตฌ์„ฑ ์š”์†Œ์— ๋Œ€ํ•œ ์ฐธ์กฐ๊ฐ€ ๋ฐฐ์—ด ์žฌ์ •๋ ฌ ํ›„ ๋Š์Šจํ•ด์ง‘๋‹ˆ๋‹ค.

๋™์ ์œผ๋กœ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋งŒ๋“ค๊ณ  DnD๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒฝ์šฐ ์ผ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด Date.now() ์—์„œ ๊ฐ ๊ตฌ์„ฑ ์š”์†Œ์— ๋Œ€ํ•œ ๊ณ ์œ  ํ‚ค๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด์ด๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

{this.state.rows.map(function(row, key) {
  return (<RowComponent key={row.id} index={key} id={row.id} moveRow={that.moveRow} />);
})}

row.id ๋Š” ๊ฐ ๊ตฌ์„ฑ ์š”์†Œ์— ๋Œ€ํ•ด ๊ณ ์œ ํ•ฉ๋‹ˆ๋‹ค.

์™œ ์ž‘๋™ํ•˜๋Š”์ง€ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜์ง€๋งŒ node-uuid's v4 ์ƒ์„ฑ ํ•œ ์ž„์˜์˜ ํ‚ค ๋Œ€์‹  model.id๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค. ์ ์–ด๋„ ๋” ์ด์ƒ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ‚ค๋ฅผ ์ˆ˜์ •ํ•ด๋„ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
์ด๊ฒƒ์€ ๋‚ด ์ฝ”๋“œ์˜€์Šต๋‹ˆ๋‹ค.

           <ContentPatch>
             {tasks.loading 
              ? <div>...loading </div>
              : this.state.containers.map((item, i) => {
                  return (
                    <TaskStage
                      key={item.id}
                      item={item}
                      tasklist={tasks.tasks}
                      onDropped={this.handleDropped}
                      onBeginningDrag={this.onBeginningDrag}
                    />
                  );
                })}
          </ContentPatch>

๋ชจ๋“  ๋“œ๋กญ ๋œ ์ž‘์—… ํ›„ ๋ชจ๋“  ํ•ญ๋ชฉ์„ ๋งคํ•‘ํ•˜๊ณ  ๋™์ผํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ๋‚˜๋Š” ๋‚ด ์ƒํƒœ๋ฅผ

...
{tasks.loading && tasks.tasks.length===0
 ? <div>...loading </div>
...

๊ทธ๋ฆฌ๊ณ  ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ํ•œ ๋ฒˆ ๋งˆ์šดํŒ…์ด์ด ์˜ค๋ฅ˜์˜ ์›์ธ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‚ด ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ๋™์ผํ•œ DragSource ๋ฐ DragTarget ๊ตฌ์„ฑ ์š”์†Œ
  • ๋“œ๋กญ์‹œ ๊ฒฝ๋กœ๋ฅผ ํƒ์ƒ‰ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

๋ฐํ˜€ endDrag ( DragSource ํ›„ ๋ฒ•) ํ™”์žฌ drop ( DropTarget ๋ฐฉ๋ฒ•). ๋‚˜๋Š” ๋ชจ๋‹ˆํ„ฐ์˜ ์ƒํƒœ๋ฅผ ๊นจ๋œจ๋ฆฌ๋Š” drop ๋‚ด์—์„œ ๊ฒฝ๋กœ ํƒ์ƒ‰์„ ์ฒ˜๋ฆฌํ•˜๊ณ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

ํ•ด๋‹น ๋…ผ๋ฆฌ๋ฅผ endDrag ํ•˜์—ฌ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฆฌํŒฉํ† ๋ง์—๋Š” monitor.didDrop() ๋“œ๋กญ์ด ์™„๋ฃŒ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ํฌํ•จ๋˜์—ˆ์ง€๋งŒ ๊ทธ๋ ‡๊ฒŒ ๋‚˜์˜์ง€๋Š” ์•Š์•˜์Šต๋‹ˆ๋‹ค.

๋‚˜๋„์ด ๋ฌธ์ œ๊ฐ€์žˆ๋‹ค. ์ œ ๊ฒฝ์šฐ๋Š” ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋“œ๋กญ ๋Œ€์ƒ์ด์ž ๋“œ๋ž˜๊ทธ ์†Œ์Šค ์ธ ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. endDrag ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ์‹œ๋„ํ–ˆ๊ณ  ํŒจ์น˜ ๋œ ๋ฐฑ์—”๋“œ (https://gist.github.com/nickpresta/eb5cce69d650db4c2795)๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋Š” ํ•ด๊ฒฐ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

๋‚ด ๊ตฌ์„ฑ ์š”์†Œ :

@DropTarget<HeadColOwnProps>(TaskDndTypes.headCol, headColTargetSpec, headColTargetCollector)
@DragSource<HeadColOwnProps>(TaskDndTypes.headCol, headColSourceSpec, headColSourceCollector)
class HeadColComponent extends React.Component<any, void> {
    render() {
        const props = this.props;
        return this.props.dndConnectDropTarget(
            this.props.dndConnectDragPreview(
                <div>
                    <div className={block('panels-task__drag')({start: props.dndIsDragging})}>
                        <SortingIcon
                            label={props.label}
                            arrowIsVisible={props.sortingIsPossible}
                            direction={props.sortingDirection}
                            clickHandler={props.sortingHandler}
                        />
                        {this.props.dndConnectDragSource(
                            <span className="panels-task__drag-control">
                                <SVGIcon width={10} height={10} url={'#icon-drag-and-drop-cell'} />
                            </span>
                        )}
                    </div>
                </div>
            )
        );
    }
}

์‚ฌ์šฉ ์˜ˆ :

const renderHeadCellId = (): JSX.Element => {
        return (
            <TaskCellHead key="key-head-col-id" modifications={{ number: true }}>
                <HeadColComponent
                    label="#"
                    key="key-dnd-head-col-id"
                    taskColType={TaskCols.id}
                    sortingIsPossible={false}
                    taskColsOrder={taskStore.orderCols}
                    updateDragProcess={(dp: TaskColDragProcess | null) => taskStore.updateDragProcess(dp)}
                    updateOrderCols={(order: TaskCols[]) => taskStore.updateOrderCols(order)}
                    dragProcess={taskStore.dragProcess}
                />
            </TaskCellHead>
        );
    };

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์„ค์ • :

const headColSourceSpec: DragSourceSpec<HeadColOwnProps> = {
    beginDrag(props: HeadColOwnProps): DraggedItem {
        return { sourceColType: props.taskColType };
    },
    canDrag(props: HeadColOwnProps): boolean {
        return props.taskColsOrder.length > 1;
    },
    endDrag(props: HeadColOwnProps, monitor: DragSourceMonitor): void {
        console.debug('endDrag');
        if (!monitor.didDrop()) {
            return;
        }
        console.debug('endDrag finish');
        props.updateOrderCols((monitor.getDropResult() as DroppedResult).newOrderCols);
    }
};

const headColTargetSpec: DropTargetSpec<HeadColOwnProps> = {
    drop(props: HeadColOwnProps, monitor: DropTargetMonitor): DroppedResult {
        console.debug('drop');
        return {
            newOrderCols: getNewOrder((monitor.getItem() as DraggedItem).sourceColType, props.taskColsOrder, props.dragProcess)
        };
    },
    hover(props: HeadColOwnProps, monitor: DropTargetMonitor, component: HeadColComponent): Object | void {
        if (!monitor.canDrop()) {
            return;
        }
        // ...
        props.updateDragProcess(currentDragProcess);
    },
    canDrop(props: HeadColOwnProps, monitor: DropTargetMonitor): boolean {
        return props.taskColType !== (monitor.getItem() as DraggedItem).sourceColType;
    }
};

const headColSourceCollector = (connect: DragSourceConnector, monitor: DragSourceMonitor) => ({
    dndConnectDragSource: connect.dragSource(),
    dndConnectDragPreview: connect.dragPreview(),
    dndIsDragging: monitor.isDragging()
});

const headColTargetCollector = (connect: DropTargetConnector, monitor: DropTargetMonitor) => {
    return {
        dndConnectDropTarget: connect.dropTarget(),
        dndIsOverCurrent: monitor.isOver({ shallow: true })
    };
};

์žฌ์ •๋ ฌ ํ›„ endDrag ๋Š” ํ˜ธ์ถœ๋˜์ง€ ์•Š์ง€๋งŒ drop ๋Š” ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ํ–‰์€ ์‹คํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

endDrag(props: HeadColOwnProps, monitor: DragSourceMonitor): void {
        console.debug('endDrag');
        if (!monitor.didDrop()) {
            return;
        }
        console.debug('endDrag finish');
        props.updateOrderCols((monitor.getDropResult() as DroppedResult).newOrderCols);
    }

๋‚ด๊ฐ€ ๋„๋Œ€์ฒด โ€‹โ€‹๋ญ˜ ์ž˜๋ชปํ•˜๊ณ ์žˆ๋Š” ๊ฒ๋‹ˆ๊นŒ? ์–ด๋–ค ์•„์ด๋””์–ด?

HTML5Backend๋ฅผ Touch Backend๋กœ ๊ต์ฒดํ–ˆ์Šต๋‹ˆ๋‹ค (https://github.com/yahoo/react-dnd-touch-backend). ๊ทธ๊ฒƒ์€ ๋‚˜๋ฅผ ์œ„ํ•ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์ €์—๊ฒŒ๋Š” ๋“œ๋กญ์‹œ ์ฝœ๋ฐฑ์— ์ค‘๋‹จ ์ ์ด ์„ค์ •๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—์ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ํฅ๋ฏธ๋กœ์šด ์ ์€ ๋ชจ๋“  ์ค‘๋‹จ ์ ์ด ๊ณ„์†๋˜๊ณ  ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ผ์‹œ ์ค‘์ง€๋˜์ง€ ์•Š์€ ํ›„์—๋„ ์‹คํŒจํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ค‘๋‹จ ์ ์„ ์ œ๊ฑฐํ•˜์ž๋งˆ์ž ์ž๋ฆฌ๋ฅผ ๋น„์šธ ๋•Œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํŒจํ‚ค์ง€๋ฅผ react-dnd-touch-backend๋กœ ๋Œ€์ฒดํ–ˆ์ง€๋งŒ ์‹ค์ œ๋กœ ๋ฌธ์ œ ํ•ด๊ฒฐ์— ๋„์›€์ด๋˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ์ฐจ๋ผ๋ฆฌ html5๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ณต๊ธฐ์— ์˜ํ•ด ์ธ์‡„๋˜๋Š” ๋ชจ๋“  ์š”์†Œ์— ํ‚ค ์„ค์ •์„ ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋ชจ๋“  ๋ Œ๋”์—์„œ ๋“œ๋ž˜๊ทธ ๊ฐ€๋Šฅํ•œ ๊ตฌ์„ฑ ์š”์†Œ์— HOC๋ฅผ ๋‹ค์‹œ ์ ์šฉํ•˜๊ณ  ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•ญ์ƒ ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— react-dnd๋ฅผ ํ˜ผ๋™ํ–ˆ์Šต๋‹ˆ๋‹ค.

@hakunin์ด์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐ

๊ทธ ์ดํ›„๋กœ ๋‚ด๊ฐ€ ๊ฐ€์ง€๊ณ ์žˆ๋Š” ๋ชจ๋“  DnD ์ฝ”๋“œ๋ฅผ ๋ฆฌํŒฉํ† ๋งํ–ˆ๊ณ  ๋“œ๋ž˜๊ทธ๋ฅผ ์‹œ์ž‘ํ•  ๋•Œ ์—ฌ์ „ํžˆ ๊ทธ๊ฒƒ์„ ์–ป์Šต๋‹ˆ๋‹ค. ์ด์ œ ๋ชจ๋“  ์ฝ”๋“œ๋ฅผ ๋‹จ์ผ util ํŒŒ์ผ๋กœ ์˜ฎ๊ธฐ๊ณ  ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ค์—ˆ์œผ๋ฏ€๋กœ ๋งˆ์นจ๋‚ด ์–ด๋–ค ์‹œ์ ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์ด์œ ๋ฅผ ์ฐพ์„ ์ˆ˜์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ํ•  ๋•Œ ์—ฌ๊ธฐ์— ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ๊ฒŒ์‹œํ•ฉ๋‹ˆ๋‹ค. (๋งˆ์šฐ์Šค ์„ค์ • btw์—์„œ TouchBackend๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค)

์‘๋‹ต ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋“œ๋ž˜๊ทธํ•˜๋Š” ๋™์•ˆ ๋‹ค๋ฅธ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ ํ›„์— ๋งŒ์ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋‹น์‹ ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ž…๋‹ˆ๊นŒ?

๋‚ด๊ฐ€ ๋Œ๊ธฐ ์‹œ์ž‘ํ•  ๋•Œ๋งˆ๋‹ค ๋‚ด ๋ถˆํ‰์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚ด ๊ฒฝ์šฐ์—๋Š” endDrag (props, monitor, component)์˜ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ํ•ญ๋ชฉ์ด ์‚ญ์ œ ๋œ ํ›„ ์ •์˜๋˜์ง€ ์•Š์€ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋‚ด ์›๋ž˜ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ "Cannot call hover after drop"๋ฉ”์‹œ์ง€์˜ ์ฝ˜์†” ์ŠคํŠธ๋ฆผ์ด ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด ๋Œ“๊ธ€ ๋•๋ถ„์—์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜์žˆ์—ˆ์Šต๋‹ˆ๋‹ค : https://github.com/react-dnd/react-dnd/issues/431#issuecomment -317219509

๋‚˜๋Š” ์ „์— ๋‹ค๋ฅธ ์žกํžˆ์ง€ ์•Š์€ ์˜ค๋ฅ˜๋ฅผ ์ผ์œผ์ผฐ์„ ๋•Œ ์ด๊ฒƒ์„ ๋งŒ๋‚ฌ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์˜ค๋ฅ˜๊ฐ€ ์—†์—ˆ์„ ๋•Œ์ด ์˜ค๋ฅ˜๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์ œ ๊ฒฝ์šฐ์—๋Š” endDrag์—์„œ ์˜ค๋ฅ˜๋ฅผ ์ผ์œผํ‚ค๋Š” ์ผ๋ถ€ ์ž‘์—… / ๊ธฐ๋Šฅ์„ ํ˜ธ์ถœ ํ•  ๋•Œ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์žกํžˆ์ง€ ์•Š์€ ์˜ค๋ฅ˜๊ฐ€ dnd๋ฅผ ๋ฉˆ์ท„์Šต๋‹ˆ๋‹ค. endDrag ๋ธ”๋ก์—์„œ ์ผ๋ถ€ ํ•จ์ˆ˜ / ์ž‘์—…์„ ํ˜ธ์ถœ ํ•  ๋•Œ try catch๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
endDrag: (props, monitor) => { try { handleEndDrag(); } catch(errror) { console.error(error)} }

onDrop ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ ๋””๋ฒ„๊ฑฐ ๋ฌธ๋„ ์˜ค๋ฅ˜์˜ ์›์ธ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์„ ์ œ๊ฑฐํ•˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ์‚ฌ๋ผ์ง€์ง€๋งŒ ๊ทธ๊ฒƒ ์—†์ด๋Š” ๋””๋ฒ„๊น…ํ•˜๋Š” ๋ฐ ์–ด๋ ค์›€์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋””๋ฒ„๊ฑฐ๊ฐ€์ด ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ์ด์œ ๋ฅผ ์•„์‹ญ๋‹ˆ๊นŒ?

๊ด€์‹ฌ์ด ์žˆ๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์ง€๋งŒ Electron ์•ฑ์„ ์‹คํ–‰ ์ค‘์ž…๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋Š” ์ตœ๊ทผ ํ™œ๋™์ด ์—†์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ž๋™์œผ๋กœ ์˜ค๋ž˜๋œ ๊ฒƒ์œผ๋กœ ํ‘œ์‹œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋” ์ด์ƒ ํ™œ๋™์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์œผ๋ฉด ํ์‡„๋ฉ๋‹ˆ๋‹ค. ๊ท€ํ•˜์˜ ๊ธฐ์—ฌ์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰