---
# System prepended metadata

title: 'Brainstorming: Use Effect'

---

# Brainstorming: Use Effect

```typescript=
import {invalidate, useState} from '@builder.io/qwik';

interface WeatherState {
  temp: number;
}

interface WeatherProps {
  city: string;
}

function fetchWeather(props: WeatherProps, state: WeatherState) {
  const data = await(await(fetch(`.../${props.city}`)).json());
  state.temp = data.temp;
}

function IntervalUpdate(this: WeatherState, props: WeatherProps): number {
  let intervalId = setInterval(fetchWeather, 1000, props, this);
  return [intervalId, () => clearInterval(intervalId)];
}


function useWeather(props: WeatherProps) {
  const state = useState<WeatherState>({temp: null});
  onResume(() => useTransient(state, IntervalUpdate, props));
  onHalt(() => releaseTransient(state, IntervalUpdate));
  useWatcher(() => fetchWeather(props, state), [props]);
  return state;  
}

const Weather = qComponent((props: {city: string}) => {
  const weatherProps = useState({city: props.city});
  const weather = useWeather(weatherProps);
  
  return () => (
    <div>
      <span>{weatherProps.city}</span>
      <span>{weather.temp}</span>
      <button on:click={() => invalidate(weatherProps) }>refresh</button>
    </div>
  );
});
```

```typescript=
export const x = (props: {city: string}) => {
  const weatherProps = useState({city: props.city});
  const weather = useWeather(weatherProps);
  
  onRender( () => (
    <div>
      <span>{weatherProps.city}</span>
      <span>{weather.temp}</span>
      <button on:click={() => invalidate(weatherProps) }>refresh</button>
    </div>
  ));
}
const Weather = qComponent(x);
// const Weather = qComponent(qHook('./chunk#x'));

function genericRendering(x) {
  return onRender(() => <span>{x}</span>)
  // const export s1 = () => <span>{x}</span>;
  // return onRender(qHook('./chunk#s1'))
}

const MyComp = qComponent(() => {
  
  return genericRendering('abc')
});

```

```typescript=
const MyComp = qComponent(async (proprs: {}) => {
  const result = await HUGE_LIBRARY_NODE();
  const state = useState(result.value);
    
  onRender(() => <span>{state}</span>);
  return () => <span>{state}</span>;
})
```

transform to:
```typescript=
const s1 = () => {
  const [state] = useClosure();
  return <span>...</span>;
}
const s2 = () => {
  const [state] = useClosure();
  return <span>...</span>;
}
const s3 = (proprs: {}) => {
  const result = await HUGE_LIBRARY_NODE();
  const state = useState(result.value);
    
  onRender(qHook(`./chunk#s1`, [state])); // <== consider not supporting
  return qHook(`./chunk#s2`, [state]); // <=== Preffered
}

const MyComp = qComponent(qHook('./chunk#s3'));


const Weather = qComponent((props: {}) => {
  onMount: () => {
  const weatherProps = useState({city: props.city});
  const weather = useWeather(weatherProps);

}
    onRender: () => {
        <div>
      <span>{weatherProps.city}</span>
      <span>{weather.temp}</span>
      <button on:click={() => invalidate(weatherProps) }>refresh</button>
    </div>
}
  
  onRender(() => (
    <div>
      <span>{weatherProps.city}</span>
      <span>{weather.temp}</span>
      <button on:click={() => invalidate(weatherProps) }>refresh</button>
    </div>
  ));
});
```

## Clock use case:

```typescript=
import {useInterval} from '@builder.io/qwik';

export Clock = qComponent((props: {}) => {
  const time = useInterval(qFn(() => ({value: new Date()}), 1000));
  onRender(() => <span>{time.value}</span>);
});
```

# `useInterval`
```typescript=
import {cleanupTuple, useState} from '@builder.io/qwik';

export function IntervalUpdate(fn: QFunction, returnValue: {}, delay: number) {
  let intervalId = setInterval(() => assign(returnValue, await fn.invoke()), delay);
  return cleanupTuple([intervalId, () => clearInterval(intervalId)]);
}

export function useInterval(fn: QFunction, delay: number) {
  const state = useState();
  onResume(() => useTransient(state, IntervalUpdate, fn, state, delay));
  onHalt(() => releaseTransient(state, IntervalUpdate));
  return state;
}
```

## Refresh use-case:
```typescript=
export MyCmp = qComponent((props: {a, b}) => {
  const state = useState({ value: 0});
  useEffect((a, b) => {
    state.value = a + b;
  }, [props.a, props.b]);
  onRender(() => <span>{stock}</span>)
});
```
Problem:
- By listing dependencies explicitly there is no way to rerun the reading of the deps. We don't know that we will have to re-run when `props.a` or `props.b` changes.

```typescript=
export MyCmp = qComponent((props: {a, b}) => {
  const state = useState({ value: 0});
  const c = foo();
  useEffect(() => state.value = props.a + props.b + c.bar);
  useEffect(($) => state.value =  $(props).a + $(props).b + $(c).bar);
  // export const effectSymbol = () => {
  //   const [state] = getClosure();
  //   return state.value = props.a + props.b;
  // }
  // useEffect(qHook('.chunk#effectSymbol{*state}|*props.a.b'))
  onRender(($) => (<span>{$(stock).price}</span>));
});
```
Problem: 
- By not listing dependencies explicitly we can use proxy to figure out what we need to listen on. But the `useEffect` function must be synchronous as we will not be able to tell async reads with which `useEffect` they go with!
- As of right now the tracking system is object level only (not prop level). Do we care?


```htmlembedded=
<div 
     q:render="./path#renderSymbol{*state}|*state"
     q:effect="./path#effectSymbol{*state}|*props.propA.propB,*otherState.propC"
     q:obj="abc xyz"
     >
</div>
```


```typescript=
export function useMemo(fn: QFunction, deps: QSerializable[]): QObject {
  let value;
  useEffect((fn) => value = await fn.invoke(), fn);
  return value;
}
```

```typescript=
export const MyComp = qComponent(() => {
  const state = useState({count:0})
  const interval = useInterval(1000);
  useEffect(
    (timestamp: number) => state.count++, 
    [propOf(interval, 'timestamp')]
  );
  // q:effect="./chunk#symbol{state}|interval.timestamp"
  onRender(() => <span>{state}</span>)
})
```


---

# Manu's `useInterval`
```typescript=
import {cleanupTuple} from '@builder.io/qwik';

export function IntervalUpdate(fn: QFunction, delay: number) {
  let intervalId = setInterval(() => await fn.invoke(), delay);
  return cleanupTuple([intervalId, () => clearInterval(intervalId)]);
}



document.load => whatever

function idealUseInterval(fn, delay) {
 useEffect(() => {
    let thing = setInterval(() => fn(), delay);
    return () => {
     clearInterval(thing);
    }
  }, [fn, delay]); 
}


export function useInterval(fn: QFunction, delay: number) {
  const value = useState({count: 0});
  onResume(() => useTransient(value, IntervalUpdate, fn, delay));
  onHalt(() => releaseTransient(value, IntervalUpdate));
  return value;
}
```

## Clock use case 2

```typescript=
import {useInterval} from '@builder.io/qwik';


export function useClockWithFunction = (fn, tickTime) => {
  const state = useState({count: 0});
  
  onResume(() => {
    useEffect(() => {
        const timer = setInterval(()=>{
            fn();
        }, tickTime);  
        return () => clearInterval(timer);
      });  
  })
}

export ClockImplemention = (props: {}) => {
 
    useClockWithFunction
    
  // 0, Unserializable
    
  onMount(() => {
      setTimeout()
  });
};

import css from './cmp.css'
           
export Clock = qComponent((props: {}) => {
  withTag('bar');
      
  return <Foo>{state}</Foo>);
});


/** @qwik */
function Foo() {
    return <button></button>
}


function genericRender(state) {
    return () => {
        
    }
}
```
---


```typescript=
export const x = () => {
  return foo();
};

export MyComp = qComponent(x)

export foo() {
  return () => <span></span>
}
```

- using onRender()
- qComponent takes an arrow function

```typescript=
import {expr, expr2} from './bar'

MARKER_FN(expr())
// export const s1 = expr()
// MARKER_FN(qHook('./chunk/s1'))


<div on:___={expr2}>
// export cnst s2 = expr2
// <div on:__={qHook('./chunk#s2')}
```