Search code examples
typescriptsolid-js

run createEffect only for specific setSignal which fires on user interaction


I am trying to build a text editor, where _cursor is position of the cursor. setInterval 4000 seconds is like user moving the cursor. In which case I want to run an effect.

But often I set the cursor as a side effect internally, for example when some text is deleted or added or an undo. In that case I don't want to run the createEffect in the example.

So how do I make the createEffect only run for second setInterval 4000 and not for the first setInterval.

import { render } from "solid-js/web";
import { For, createSignal, createEffect, on } from "solid-js";

function Counter() {
   const [_cursor, _setCursor] = createSignal(100)
  

  createEffect(on(_cursor, (v, p) => {
     if (p && v < p) {
        console.log('reset')
     }
  }))

  setInterval(() => {
     _setCursor(_cursor() - 1)
  }, 500)

  setInterval(() => {
     _setCursor(_cursor() - 1)
  }, 4000)


  return (<>
     <span>{_cursor()}</span>
    </>)
}

render(() => <Counter />, document.getElementById("app"));

Solution

  • You can set another flag and use its value to control the execution of the effect:

      const [flag, setFlag] = createSignal(true);
    
      createEffect(on(_cursor, (v, p) => {
        if (flag()) return;
        if (p && v < p) {
          console.log('reset')
        }
      }));
    

    Please note that, the effect does not track the flag:

    import { createEffect, createSignal, on } from "solid-js";
    import { render } from "solid-js/web";
    
    function Counter() {
      const [cursor, setCursor] = createSignal(100);
      const [flag, setFlag] = createSignal(true);
    
      createEffect(on(cursor, (v, p) => {
        if (flag()) return;
        if (p && v < p) {
          console.log('reset')
        }
      }))
    
      setInterval(() => {
        setCursor(cursor() - 1);
      }, 500);
    
      setInterval(() => {
        setCursor(cursor() - 1)
      }, 4000);
    
      // This is for demonstrating the logic
      setInterval(() => setFlag(!flag()), 1000);
    
      return (
        <>
          <span>{cursor()}</span>
        </>
      )
    }
    
    render(() => <Counter />, document.getElementById("app"));