TIL

2024.06.10 drag_๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ_์—†์ด_๊ตฌํ˜„_์ค‘_ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… 1

inz1234 2024. 6. 12. 22:24

๐Ÿšจ  TroubleShotting

๋“œ๋ž˜๊ทธ๋ฅผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—†์ด mouseEvent๋กœ ๊ตฌํ˜„ํ•ด๋ณด๊ณ  ์žˆ๋˜ ์ค‘,
๋“œ๋ž˜๊ทธ๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ํ•˜๋ฉด ์ด์ „์— ๋งˆ์ง€๋ง‰์œผ๋กœ ๋“œ๋ž˜๊ทธ ํ–ˆ๋˜ ์š”์†Œ์—์„œ ๋” ๋“œ๋ž˜๊ทธ ๋˜์ง€ ์•Š๊ณ 
์ž๊พธ ์ฒ˜์Œ์œผ๋กœ ๋Œ์•„๊ฐ€๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ–ˆ๋‹ค.

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


๋ฌธ์ œ ๋ฐœ์ƒ์˜ ๋ฐฐ๊ฒฝ - As Is

  const [startMoveX, setStartMoveX] = useState(0);
  const [mouseDown, setMouseDown] = useState(false);
  const [movingX, setMovingX] = useState(0);

const handleMouseDown = (clickEvent: React.MouseEvent<Element, MouseEvent>) => {
    setMouseDown(true);
    setStartMoveX(clickEvent.screenX);
  };

  const handleMouseUp = (mouseUpEvent: React.MouseEvent<Element, MouseEvent>) => {
    setMouseDown(false);
 };

  const handleMouseMove = (moveEvent: React.MouseEvent<Element, MouseEvent>) => {
    setMovingX(moveEvent.screenX);
  };

  return (
    <div className="w-full overflow-hidden" ref={containerRef}>
      <div
        className="flex flex-nowrap gap-4 h-[300px] w-max overflow-x-visible"
        onMouseDown={handleMouseDown}
        onMouseUp={handleMouseUp}
        onMouseMove={ handleMouseMove }
        style={{
          transform: `translateX(${mouseDown ? movingX - startMoveX : null}px)`
        }}

mouseDown ๋˜์—ˆ์„ ๋•Œ์˜ ์œ„์น˜๋ฅผ startMoveX๋ผ๋Š” state๋กœ ๊ด€๋ฆฌํ•˜๊ณ 
mouseMove ์ค‘์˜ ์œ„์น˜๋ฅผ movingX๋ผ๋Š” state๋กœ ๊ด€๋ฆฌํ•œ ๋’ค,
movingX - startMoveX  ๊ฐ’์„ ์ด๋™๊ฑฐ๋ฆฌ๋ผ ํŒ๋‹จํ•˜์—ฌ style์— ์ด๋™๊ฑฐ๋ฆฌ๋งŒํผ translateX๋กœ ์ ์šฉํ–ˆ๋‹ค.


Why(์ด์œ ) ?

๋“œ๋ž˜๊ทธ๋Š” ๋งค ํ”„๋ ˆ์ž„๋งˆ๋‹ค ์ž‘์€ ์ด๋™์ด ๋ชจ์—ฌ์„œ ๊ตฌํ˜„๋œ๋‹ค.
์ฆ‰ [---] ์ด๊ฒŒ ํ•œ ํ”„๋ ˆ์ž„์ด๋ผ๊ณ  ํ•˜๋ฉด, [ ์—์„œ ์‹œ์ž‘ํ•ด์„œ --- ๋งŒํผ ์ด๋™ํ•˜๊ณ  ]  ๊ฐ€ ๋˜์–ด์•ผ ํ•œ ํ”„๋ ˆ์ž„์ด ๋๋‚œ๋‹ค.
์ด๋Ÿฐ ํ”„๋ ˆ์ž„๋“ค์ด ๋ชจ์—ฌ์„œ ํ•œ ๋ฒˆ์˜ ๋“œ๋ž˜๊ทธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

์šฐ์„  handleMouseMove ํ•จ์ˆ˜ ๋‚ด์— ์ด๋™๊ฑฐ๋ฆฌ๋ฅผ ๊ฐฑ์‹ ํ•˜๋Š” ๋กœ์ง์€ ์˜ค์ง mouseDown์ด true ์ผ ๋•Œ๋งŒ ์‹คํ–‰๋˜์–ด์•ผ ํ–ˆ๊ณ 

1. ์ด๋™๊ฑฐ๋ฆฌ๋Š” ๋ˆ„์ ๋˜์–ด์•ผ ํ–ˆ๋‹ค.

์ด๋™๊ฑฐ๋ฆฌ๊ฐ€ ๋ˆ„์ ๋˜์–ด์•ผ ํ”„๋ ˆ์ž„๋“ค์ด ๋ชจ์—ฌ์„œ ํ•œ ๋ฒˆ ๋“œ๋ž˜๊ทธ์˜ ์ด ์ด๋™๊ฑฐ๋ฆฌ๊ฐ€ ๋‚˜์˜จ๋‹ค.
๋ˆ„์ ๋˜์ง€ ์•Š์œผ๋ฉด ์ œ์ผ ๋งˆ์ง€๋ง‰ ํ”„๋ ˆ์ž„์—์„œ์˜ ์ด๋™๊ฑฐ๋ฆฌ๋งŒ ์ธก์ •์ด ๋˜์–ด ์ž๊พธ ์›์ ์œผ๋กœ ๋Œ์•„๊ฐ€๋ฒ„๋ ธ๋˜ ๊ฒƒ์ด๋‹ค.
๋ˆ„์ ๋˜๋Š” ๊ฐ’์€ ๊ณ„์† ๋ณ€ํ•˜๋Š” ๊ฐ’์ด๋ฏ€๋กœ position์ด๋ผ๋Š” state๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค์—ˆ๊ณ , handleMouseMove ํ•จ์ˆ˜๋ฅผ ์ด๋ ‡๊ฒŒ ๋ฐ”๊ฟจ๋‹ค.

์‹œํ–‰์ฐฉ์˜ค 1

  
const [position, setPosition] = useState(0);
...
   const handleMouseMove = (moveEvent: React.MouseEvent<Element, MouseEvent>) => {
   if(mouseDown) {
    setMovingX(moveEvent.screenX);
    setPosition((prev) => prev + (movingX - startMoveX));
   } 
  };
  
    return (
    <div className="w-full overflow-hidden" ref={containerRef}>
      <div
        className="flex flex-nowrap gap-4 h-[300px] w-max overflow-x-visible"
        onMouseDown={handleMouseDown}
        onMouseUp={handleMouseUp}
        onMouseMove={handleMouseMove}
        style={{
          transform: `translateX(${mouseDown ? position : null}px)`
        }}
      > 
      ...

๊ทผ๋ฐใ…‹ใ…‹ใ…‹ ์ด๋ ‡๊ฒŒ ๋ฐ”๊ฟจ๋”๋‹ˆ ์กฐ๊ธˆ๋งŒ ๋“œ๋ž˜๊ทธ๋ฅผ ํ•ด๋„ ์—„์ฒญ๋‚˜๊ฒŒ ์ด๋™ํ•ด๋ฒ„๋ ธ๋‹ค.
console.log(position)์„ ํ–ˆ๋”๋‹ˆ 3519 ๋ผ๋Š” ์ˆซ์ž๊ฐ€ ๋‚˜์™”๋‹ค.
์‹ค์ œ๋กœ๋Š” ํ•œ 50px ํ•œ ๊ฒƒ ๊ฐ™์€๋ฐ..

2. ์‹œ์ž‘์ (startMoveX)

์ด๋™๊ฑฐ๋ฆฌ๋ฅผ movingX - startMoveX๋กœ ํ•ด๋‘์—ˆ๋Š”๋ฐ, 
startMoveX๋Š” mouse๊ฐ€ ์•„๋ฌด๋ฆฌ ์›€์ง์—ฌ๋„ ๊ณ„์† ์ฒ˜์Œ ํด๋ฆญํ•œ ๊ณณ์ด์ง€ ์•Š์€๊ฐ€?
๊ทธ๋Ÿฌ๋‹ˆ, ๋งˆ์šฐ์Šค๋ฅผ ๋งŽ์ด ์›€์ง์ด๋ฉด ์›€์ง์ผ์ˆ˜๋ก movingX - startMoveX๊ฐ€ ๊ณ„์† ๋Š˜์–ด๋‚ฌ๊ณ  ๊ทธ๊ฒŒ ๋ˆ„์ ์ด ๋˜์–ด 3519 ๋ผ๋Š” ์–ด๋งˆํ•œ ์ˆซ์ž๊ฐ€ ๋‚˜์™”๋˜ ๊ฒƒ์ด๋‹ค.

startMoveX๋ฅผ ๋งˆ์šฐ์Šค๊ฐ€ ์›€์ง์ผ ๋•Œ๋งˆ๋‹ค ๊ฐฑ์‹ ํ•ด์ค˜์•ผ๊ฒ ๋‹ค!
ํ•˜์—ฌ handleMouseMove์— setStartMoveX() ๋กœ์ง์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

์‹œํ–‰์ฐฉ์˜ค 2

  const handleMouseMove = (moveEvent: React.MouseEvent<Element, MouseEvent>) => {
    if (mouseDown) {
      setMovingX(moveEvent.screenX);
      setStartMoveX(moveEvent.screenX);
      setPosition((prev) => prev + (movingX - startMoveX));
    }
  };

๊ทผ๋ฐ ๋˜ ์ด๋žฌ๋”๋‹ˆ, ์ด๋ฒˆ์—๋Š” ๋‚ด๊ฐ€ ์›€์ง์ธ ๋งŒํผ๋งŒ ์ด๋™ํ•˜๋Š”๋ฐ ๋Š๊ฒจ์„œ ๋ก ๋ก ๋“œ๋ž˜๊ทธ๊ฐ€ ๋˜๋Š” ๊ฒŒ ์•„๋‹Œ๊ฐ€..

์•„๋‹ˆ ์ด๋ ‡๊ฒŒ ๋ปฃ๋ปฃํ•œ ๋“œ๋ž˜๊ทธ๋ฅผ ์›ํ•œ ๊ฒŒ ์•„๋‹ˆ์—ˆ๋Š”๋ฐ...

3. ๋งˆ์šฐ์Šค ์›€์ง์ž„๊ณผ ๋™์‹œ์— ์ด๋™๊ฑฐ๋ฆฌ ๊ฐฑ์‹ 

setMovingX๋ฅผ ํ•œ ๋’ค์— -> ์ด๋™๊ฑฐ๋ฆฌ๊ฐ€ ๊ฐฑ์‹ ์ด ๋˜๋‹ˆ ๋‹น์—ฐํ•œ ๊ฒฐ๊ณผ์˜€๋‹ค. 
์ฆ‰, ๋งˆ์šฐ์Šค๊ฐ€ ์›€์ง์ด๋Š” ๋™์‹œ์— ์ด๋™๊ฑฐ๋ฆฌ๊ฐ€ ๊ฐฑ์‹ ์ด ๋˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ,
์›€์ง์ด๊ณ  ๊ทธ๊ฑธ setMovingX๋ฅผ ํ•œ ๋’ค์— re-๋ Œ๋”๋ง์ด ๋œ ํ›„ ๊ณ„์‚ฐ๋œ ๊ฒฐ๊ณผ๋ฌผ์ด ๋ณด์—ฌ์กŒ๋˜ ๊ฒƒ.
๊ทธ๋ž˜์„œ movingX state๋ฅผ ์—†์•ด๋‹ค. ๊ทธ๋ƒฅ ๋ฐ”๋กœ moveEvent.screenX์—์„œ startMoveX๋ฅผ ๋บ๋‹ค.

์‹œํ–‰์ฐฉ์˜ค 3

 const handleMouseMove = (moveEvent: React.MouseEvent<Element, MouseEvent>) => {
    if (mouseDown) {
      const deltaX = moveEvent.screenX - startMoveX;
      setPosition((prev) => prev + deltaX); // ์ด์ „ ์œ„์น˜์— ์ด๋™ ๊ฑฐ๋ฆฌ๋ฅผ ๋”ํ•จ
      setStartMoveX(moveEvent.screenX);
    } 
  };

what(๊ฒฐ๊ณผ) - To Be

์ด์ „์ฒ˜๋Ÿผ ๋“œ๋ž˜๊ทธ๋ฅผ ํ•˜๊ณ  ๋‹ค์‹œ ๋“œ๋ž˜๊ทธ๋ฅผ ํ•  ๋•Œ ์›์ ์œผ๋กœ ๋Œ์•„๊ฐ€์ง€ ์•Š๊ณ 
๋งˆ์ง€๋ง‰ ๋“œ๋ž˜๊ทธ์—์„œ ์ด์–ด์„œ ๋“œ๋ž˜๊ทธ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ฑ๊ณตํ–ˆ๋‹ค.


๐Ÿ’ก ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ๋œ ์ 

๋“œ๋ž˜๊ทธ์˜ ์ž‘๋™์›๋ฆฌ: ์ž‘์€ ํ”„๋ ˆ์ž„๋“ค์˜ ๋ชจ์ž„