Click drag and onClick in react?

Viewed 815

I am building a table. when a user clicks and drags through the cells, the cells between is highlight. But I don't know why when I onClick on a single cell it also highlights between the last cell I clicked and the new cell. I want to when I onClick it only highlight on one cell

Here is my code:

import React, {useState} from "react";
import './Style.css';

export default function Table() {
    let div = [];
    const [start, setStart] = useState(null);
    const [end, setEnd] = useState(null);
    const [selecting, setSelecting] = useState(false);

    let beginSelection = i => {
        setSelecting(true);
        setStart(i);
        updateSelection(i);
    };

    let endSelection = (i = end) => {
        setSelecting(false);
        updateSelection(i);

    };
    let updateSelection = i => {
        if(selecting) {
            setEnd(i);
        }
    };
    for(let i = 0; i <= 31; i++ ) {
        let a = (

                <span
                    key={i}
                    className={
                        ((end != null  && start != null) && (end <= i && i<= start || (start <= i && i <= end)) ? "selected": "")
                    }
                    onMouseDown={()=>beginSelection(i)}
                    onMouseUp={()=>endSelection(i)}
                    onMouseMove={()=>updateSelection(i)}
                >
                {i}
            </span>
        );
        div.push(a);
    }
    return div;
}

Here are my full code and demo: https://codesandbox.io/s/github/Kalipts/table_grid Please help me. Thanks

2 Answers

I have not tested this because I couldn't get your link to work, but I'm guessing it's because you're experiencing "asynchronous state changes". From the docs: State Updates May Be Asynchronous

In your beginSelection you are calling updateSelection, but I'm guessing the selection state is not yet actually updated when that code runs. A simple fix is to add a second parameter to your updateSelection

let updateSelection = (i, force) => {
    if (selecting || force) {
        setEnd(i);
    }
}

and then call updateSelection(i, true) from beginSelection and endSelection, but not from onMouseMove. You can also call setEnd directly from beginSelection and endSelection if that's easier. Both alternatives should work, it's more or less a matter of preference.

The problem is you set start onMouseDown and update it only onMouseMove. So your issue can be fixed by reseting start and end in onMouseDown event:

  let beginSelection = i => {
    setSelecting(true);
    setStart(i);
    setEnd(i);
    updateSelection(i);
  };

https://codesandbox.io/s/epic-newton-nlmvj

Related