noUiSlider rerenders when moving slider

Hello, I have an issue with noUiSlider(https://refreshless.com/nouislider/) i want to make a slider with 2 knobs. Everytime i move a knob on the slider, i get the following error message in the console. Uncaught Error: noUiSlider: Slider was already initialized. the code looks like this
import { createEffect, createSignal, onCleanup } from "solid-js";
import "nouislider/dist/nouislider.css";
import noUiSlider from "nouislider";

function Slider() {
const [sliderValue, setSliderValue] = createSignal<[number, number]>([
20, 80,
]);
let sliderContainer: HTMLDivElement | null = null;

// Initialize the slider when the component mounts
createEffect(() => {
if (sliderContainer) {
noUiSlider.create(sliderContainer, {
start: sliderValue(),
connect: true,
range: {
min: 0,
max: 100,
},
});

// Update sliderValue state when the slider changes
sliderContainer.noUiSlider.on("update", (values: string[]) => {
setSliderValue([parseFloat(values[0]), parseFloat(values[1])]);
});
}

return () => {
if (sliderContainer) {
sliderContainer.noUiSlider.destroy();
}
};
});

return (
<div class="slider">
<div ref={(el) => (sliderContainer = el)}></div>
<p>
Slider Values: {sliderValue()[0]} - {sliderValue()[1]}
</p>
</div>
);
}

export default Slider;
import { createEffect, createSignal, onCleanup } from "solid-js";
import "nouislider/dist/nouislider.css";
import noUiSlider from "nouislider";

function Slider() {
const [sliderValue, setSliderValue] = createSignal<[number, number]>([
20, 80,
]);
let sliderContainer: HTMLDivElement | null = null;

// Initialize the slider when the component mounts
createEffect(() => {
if (sliderContainer) {
noUiSlider.create(sliderContainer, {
start: sliderValue(),
connect: true,
range: {
min: 0,
max: 100,
},
});

// Update sliderValue state when the slider changes
sliderContainer.noUiSlider.on("update", (values: string[]) => {
setSliderValue([parseFloat(values[0]), parseFloat(values[1])]);
});
}

return () => {
if (sliderContainer) {
sliderContainer.noUiSlider.destroy();
}
};
});

return (
<div class="slider">
<div ref={(el) => (sliderContainer = el)}></div>
<p>
Slider Values: {sliderValue()[0]} - {sliderValue()[1]}
</p>
</div>
);
}

export default Slider;
Any idea what is wrong? Much appreciated.
noUiSlider - JavaScript Range Slider | Refreshless.com
noUiSlider is a lightweight, ARIA-accessible JavaScript range slider with multi-touch and keyboard support. Great for responsive designs, and no dependencies!
2 Replies
cheerful_raccoon_77015
I made it work with the help of chat gpt, lol. In case anybody is interested in the solution it looks like this:
import { createSignal, onCleanup, onMount } from "solid-js";
import noUiSlider from "nouislider";
import "./nouislider.css";

function DualSlider() {
const [sliderValues, setSliderValues] = createSignal<[number, number]>([
25, 75,
]);

const sliderRef = (element: HTMLElement | null) => {
if (element) {
onMount(() => {
noUiSlider.create(element, {
start: sliderValues(),
range: {
min: 0,
max: 100,
},
step: 1,
connect: true,
});

element.noUiSlider.on("update", (values) => {
const newValues = values.map((value) =>
parseFloat(value)
) as [number, number];
setSliderValues(newValues);
});
});

onCleanup(() => {
element.noUiSlider.destroy();
});
}
};

return (
<div class="slider">
<div id="dual-knob-slider" ref={sliderRef}></div>
<p>
Slider Values: {sliderValues()[0]} - {sliderValues()[1]}
</p>
</div>
);
}

export default DualSlider;
import { createSignal, onCleanup, onMount } from "solid-js";
import noUiSlider from "nouislider";
import "./nouislider.css";

function DualSlider() {
const [sliderValues, setSliderValues] = createSignal<[number, number]>([
25, 75,
]);

const sliderRef = (element: HTMLElement | null) => {
if (element) {
onMount(() => {
noUiSlider.create(element, {
start: sliderValues(),
range: {
min: 0,
max: 100,
},
step: 1,
connect: true,
});

element.noUiSlider.on("update", (values) => {
const newValues = values.map((value) =>
parseFloat(value)
) as [number, number];
setSliderValues(newValues);
});
});

onCleanup(() => {
element.noUiSlider.destroy();
});
}
};

return (
<div class="slider">
<div id="dual-knob-slider" ref={sliderRef}></div>
<p>
Slider Values: {sliderValues()[0]} - {sliderValues()[1]}
</p>
</div>
);
}

export default DualSlider;
foolswisdom
foolswisdom10mo ago
The issue with the original code is that it uses createEffect instead of onMount, and that it returns a cleanup function (like you would in react, but that doesn't work in solid) instead of using the onCleanup function In your corrected code, you fixed those issues, though you didn't need to use a ref function to fix it (though it's fine either way)