Closed riven314 closed 1 year ago
Hey @riven314,
Sorry for taking so long to reply to your issue! Accessing up-to-date state from within a callback is actually non trivial:
In React hooks, due to the way state is encapsulated in the functions of React.useState(), if a callback gets the state through React.useState(), it will be stale (the value when the callback was setup)
Luckily this post from Stackoverflow provides an answer
const initSeries = [1, 3.5, 5, 2.8];
const [series, setSeries] = useState(initSeries);
const stateRef = useRef();
// make stateRef always have the current series state
// the "fixed" callbacks from chartjs-plugin-dragdata
// can refer to this object whenever they need the current value.
// Note: the callbacks will not
// be reactive - they will not re-run the instant state changes,
// but they *will* see the current value whenever they do run
stateRef.current = series;
// ... later in the dragdata options, we need to reference
// stateRef.current instead of series:
onDrag: (e, datasetIndex, index, value) => {
console.log("onDrag series: ", stateRef.current);
if (
value < stateRef.current[index] - 0.5 ||
value > stateRef.current[index] + 0.5
) {
return false;
}
}
One last gotcha is that the chartjs-plugin-dragdata
mutates the charts input data (see #96),
which is why we need to create a deep clone of the series when creating the chart instance:
const data = {
labels: ["2020", "2021", "2022", "2023"],
datasets: [
{
label: "alex",
// this is necessary because the plugin
// currently mutates all input data
// see issue #96
data: JSON.parse(JSON.stringify(series)),
borderColor: "rgb(255, 99, 132)",
backgroundColor: "rgba(255, 99, 132, 0.5)"
}
]
};
Here's a working fork of your Codesandbox example https://codesandbox.io/s/draggablelinecharts-forked-d36upe?file=/src/App.js
Hope this fixes your issue! If not, please re-open
Describe the bug @chrispahm I want to bound a datapoint within a range of its current value (e.g. +/-0.5) upon dragging (e.g. if the point is 1.5, it's bounded at (1.0, 2.0), if the point is 1.0, then it's bounded at (0.5, 1.5))
To achieve this, I use
useState
to initialise the series data (i.e.series
). InonDrag
callback, I make use ofseries
to access the value before it's dragged. InonDragEnd
, I updateseries
bysetSeries
to make sure the state is sync with what the chart is showing.Here is my brief code snippet:
However, it is not working as expected because I see
series
withinonDrag
is not properly updated after some drags. But I am sureseries
has been updated, as verified in my sample code below.To Reproduce Here is my PoC code to reproduce the issue: https://codesandbox.io/s/draggablelinecharts-5dxk97?file=/src/App.js