I'd like to run some code in my component, but only once.

I cannot put it in dependency-less createEffect, since it is supposed to run some time after the component is first rendered, but it must never be run more than once during the component lifecycle. I thought I'd use a local Boolean variable for that, like this:
function MyComponent() {
const [dataLoaded, setDataLoaded] = createSignal(false);
let actionPerformed = false; // This flag ensures the action runs only once

createEffect(() => {
// This effect runs whenever `dataLoaded()` changes.
// However, the action inside will only execute the first time `dataLoaded()` is true.
if (dataLoaded() && !actionPerformed) {
console.log('Action triggered by signal and executed only once!');
// Perform your one-time action here
// For example, trigger an animation, show a notification, etc.

actionPerformed = true; // Set flag to prevent future executions
}
});

return (
<div>
<p>Data Status: {dataLoaded() ? 'Loaded' : 'Loading...'}</p>
<button onClick={() => setDataLoaded(true)}>Simulate Data Load</button>
<button onClick={() => setDataLoaded(false)}>Reset Data Status</button>
{/* Resetting data status won't re-trigger the action if it's already run */}
</div>
);
}
function MyComponent() {
const [dataLoaded, setDataLoaded] = createSignal(false);
let actionPerformed = false; // This flag ensures the action runs only once

createEffect(() => {
// This effect runs whenever `dataLoaded()` changes.
// However, the action inside will only execute the first time `dataLoaded()` is true.
if (dataLoaded() && !actionPerformed) {
console.log('Action triggered by signal and executed only once!');
// Perform your one-time action here
// For example, trigger an animation, show a notification, etc.

actionPerformed = true; // Set flag to prevent future executions
}
});

return (
<div>
<p>Data Status: {dataLoaded() ? 'Loaded' : 'Loading...'}</p>
<button onClick={() => setDataLoaded(true)}>Simulate Data Load</button>
<button onClick={() => setDataLoaded(false)}>Reset Data Status</button>
{/* Resetting data status won't re-trigger the action if it's already run */}
</div>
);
}
(incidentally, this is code generated by an LLM, which was basically identical to what I've done), but it doesn't work – the effect still runs more than once. What am I doing wrong?
4 Replies
bigmistqke
bigmistqke3mo ago
sounds like you are looking for createReaction
createReaction -
Documentation for SolidJS, the signals-powered UI framework
bigmistqke
bigmistqke3mo ago
i would do something like createReaction(on(dataLoaded, () => ...)) just to be sure it's only the dataLoaded that triggers it
zulu
zulu3mo ago
if (dataLoaded() && !actionPerformed) {
if (dataLoaded() && !actionPerformed) {
to
if ( !actionPerformed && dataLoaded()) {
if ( !actionPerformed && dataLoaded()) {
technically, your Effect may run more than once , with any change to dataLoaded()
but if you guarded the logic that need to run once with the boolean it should not have "side effects" and would work as if the effect didn't run in the fix line, checking the boolean first and short circuting it will not call the dataLoaded() and the effect should just "die" because it will observe nothing. you can make it more explicit but returning early when the flag is true, first thing in the effect body.
createEffect(() => {
if(actionPerformed) return
...
}
createEffect(() => {
if(actionPerformed) return
...
}
createReaction is also a good option as suggested
jer3m01
jer3m013mo ago
That behavior will also be default with run once Suspense in Solid 2.0

Did you find this page helpful?