Hi everyone,
I'm trying to change a global variable (an array of 4 values) when a custom component (slider with 3 handles) is modified.
I'm using an event handler in the react code:
import React, { useState, useCallback } from 'react';
import { Retool } from '@tryretool/custom-component-support';
import Slider from 'rc-slider';
import 'rc-slider/assets/index.css';
import styled from 'styled-components';
import debounce from 'lodash/debounce';
const MIN = 0;
const MAX = 100;
const TRACK_LABELS = ['Ville', 'Nationale', 'Autoroute', 'Montagne'];
const SliderWrapper = styled.div`
position: relative;
touch-action: none;
padding: 16px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
margin: 8px 0;
max-width: 800px;
`;
const SliderLabel = styled.label`
color: var(--primary-text, #0d0d0d);
font-size: 12px;
font-weight: 600;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
margin-bottom: 4px;
display: block;
`;
const StyledSliderContainer = styled.div`
.rc-slider {
margin: 20px 0;
}
.rc-slider-track {
background-color: #16a085;
}
.rc-slider-track-1 {
background-color: #3fc380;
}
.rc-slider-track-2 {
background-color: #90c695;
}
.rc-slider-handle {
border: 2px solid #16a085;
background-color: white;
width: 18px;
height: 18px;
margin-top: -7px;
&:hover,
&:focus,
&:active {
border-color: #17b261;
box-shadow: 0 0 0 5px rgba(23, 178, 97, 0.3);
}
}
`;
const SliderOutput = styled.output`
color: var(--retool-slider-output, #0d0d0db3);
font-size: var(--retool-slider-output-font-size, 12px);
line-height: var(--retool-slider-output-line-height, 16px);
font-weight: var(--retool-slider-output-font-weight, 500);
font-family: var(--retool-slider-output-font-family, Inter, sans-serif);
display: block;
margin-top: 40px;
`;
export const mSlider = () => {
// Retool states (for data persistence)
const [retoolValuesHandles, setRetoolValuesHandles] = Retool.useStateArray({
name: "valuesHandles",
initialValue: [25, 50, 75],
inspector: "text",
label: "Handles Values",
});
const [retoolRouteProportions, setRetoolRouteProportions] = Retool.useStateArray({
name: "routeProportions",
initialValue: [25, 25, 25, 25],
inspector: "text",
label: "Route Proportions",
});
// Local React states (for smooth UI)
const [localValuesHandles, setLocalValuesHandles] = useState(retoolValuesHandles);
const [localRouteProportions, setLocalRouteProportions] = useState(retoolRouteProportions);
const [labelText] = useState('Répartition du trajet (%)');
// Debounced function to update Retool state
const debouncedRetoolUpdate = useCallback(
debounce((values, proportions) => {
setRetoolValuesHandles(values);
setRetoolRouteProportions(proportions);
}, 200),
[]
);
// Add the event callback
const onProportionsChange = Retool.useEventCallback({
name: "proportionsChanged"
});
const handleSliderChange = (newValues) => {
// Update local state immediately for smooth UI
setLocalValuesHandles(newValues);
const proportions = [
newValues[0],
newValues[1] - newValues[0],
newValues[2] - newValues[1],
100 - newValues[2]
];
setLocalRouteProportions(proportions);
// Update Retool state with debounce
debouncedRetoolUpdate(newValues, proportions);
// Trigger the event with the new proportions
onProportionsChange(proportions);
};
return (
<SliderWrapper>
<SliderLabel htmlFor="custom-slider">{labelText}</SliderLabel>
<StyledSliderContainer>
<Slider
min={MIN}
max={MAX}
value={localValuesHandles} // Use local state here
onChange={handleSliderChange}
range
pushable={false}
allowCross={false}
/>
</StyledSliderContainer>
<SliderOutput>
Ville : {localRouteProportions[0]}% - Nationale : {localRouteProportions[1]}% -
Autoroute : {localRouteProportions[2]}% - Montagne : {localRouteProportions[3]}%
</SliderOutput>
</SliderWrapper>
);
};
I then added a run script action when the event is triggered:
It does update, but the problem is that the values of the global variables are updated with the previous values of the multislider.
Let's say the values of the slider are [10, 10, 10, 70].
Then user clicks and changes them to [30, 30, 30, 10].
My global variable is then updated but with the values [10, 10, 10, 70].
It seems however that in the React script, the event callback happens after the values are updated.
Any hint?
Baptiste