8
8
8XL2020-06-27 18:04:57
React
8XL, 2020-06-27 18:04:57

Drag'n'drop - why is the old state displayed in useEffect?

The bottom line: when the onMouseDown event occurs on the div('area') of the child component, motion.active : true and then the mousemove and mouseup listeners are launched, where mousup resets motion.active : false. But! After releasing the mouse button and changing its position, mousedown fires (I don’t understand how) again and sets motion.active : true and everything starts over again, which should not be.

function App() {
  
  const [motion, setMotion] = React.useState({
    active: false,
    i: null,
    stX: null,
    movX: null,
    movY: null
  })
  
  const handleMouseDown = (e, index) => {
    e.preventDefault()
    const parent = e.target.parentNode.getBoundingClientRect();
    const element = e.target.getBoundingClientRect();

    const x = element.left - parent.left;
    const y = element.top - parent.top;
    setMotion({
      ...motion,
      active: true,
      i: index,
      stX: x
    })
  }

  React.useEffect(()=>{
    window.addEventListener('mousemove', handleMouseMove);
    window.addEventListener('mouseup', handleMouseUp); 
  },[handleMouseDown])


  const handleMouseMove = (e) => {
    if(motion.active) setMotion({
      ...motion,
      movX: e.offsetX,
      movY: e.offsetY
    })
  }

  const handleMouseUp = () => {
    setMotion({
      active: false,
    })
} 

  return (
    <div className="App">
      <Panel  />
      <Search />
      <h3>{`${motion.active}__${motion.movX}++${motion.stX}`}</h3>
      <div 
        className="wrapper"
        >
        {state && state.map((item, index)=>
          <div 
            className="area"
            onMouseDown={(e)=>handleMouseDown(e, index)}>
          <MiniItem
            key={item._id}
            flag={flag}
            resetStateHidden={resetStateHidden}
            setFlag={setFlag}
            item={item}
            index ={index}
            state={state}
            motion={motion}
               
          />
          </div>
          )}
      </div>
    </div>
  );
}


Help me, I broke my whole head. How to fix motion.active flag until next mousedown.

Thank you.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
8
8XL, 2020-06-30
@8XL

Having practically brought himself to an existential crisis, he found a solution. I'll leave it in case anyone encounters state loss due to an event listener inside the useEffect hook.

React.useEffect(()=>{
// добавление слушателя на все окно
    window.addEventListener('mousemove', mouseMove); 
    window.addEventListener('mouseup', mouseUp);
    
      return () => {
// удаление слушателя после обновления эффекта
        window.removeEventListener('mousemove', mouseMove); 
        window.removeEventListener('mouseup', mouseUp);
      }             
    }
  )

// эвент движения
  const mouseMove = (e) => { 
    if(motion.active){
// считаем дельту положения мышки в моменте и первоначального положения
      const delta = e.pageY - motion.stY;

// here and below IMPORTANT to set the state functionally for the effect(!!!)!
setMotion(motion=>( 
          {
            ...motion,
            y: delta
          }
        )
      )
    }
  }

// эвент отпускания клавиши и конец днд
  const mouseUp = () =>{
    setMotion(motion=>(
      {
        ...motion,
        i: null,
        active: false,
        y: 0,
      })
    )
  }

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question