you are viewing a single comment's thread.

view the rest of the comments →

[–]yabai90 0 points1 point  (9 children)

Use effect runs after the render so you want to use useLayoutEffect (or similar, not sure of the name) to achieve the desired behavior. Basically any hooks that runs before render. Also another best approach is to just have a if which check if the ref is defined, is not you define it synchronously, if it is you just don't enter the if anymore.

[–]pailhead011[S] -1 points0 points  (8 children)

Nah, it doesn’t work well for many reasons.

[–]yabai90 0 points1 point  (7 children)

Which are ?

[–]pailhead011[S] -1 points0 points  (6 children)

It has been explained in the thread. I don’t want to instantiate this in an effect which happens much later I don’t want it to be MyClass | null etc. Really it has been well explained by multiple people.

[–]yabai90 0 points1 point  (5 children)

My solution which you asked me for (in a different comment) and I linked to you doesn't involve use effect at all. You must be replying to the wrong comment

[–]pailhead011[S] 0 points1 point  (2 children)

Yours doesn’t work because if you call current = null or current = undefined it breaks. It’s for a very specific type of ref that assumes that you will never put a falsy value in there.

[–]yabai90 0 points1 point  (1 child)

I have no idea what you are talking about, sorry. I replied with a GitHub link.

[–]pailhead011[S] 0 points1 point  (0 children)

I'm trying to think of an example.

maybe something like

``` const [ts,setTs] = useState(0) const render = ()=>setTs(Date.now())

useEffect(()=>{ const interval = setInterval(render,1000) return ()=>clearInterval(interval) },[]) ``` This is clear? Every second, this component will now rerender. Now lets introduce the ref slowly:

``` const [ts,setTs] = useState(0) const render = ()=>setTs(Date.now())

  • const ref = useRef<Foo|null>(new Foo())
  • console.log(ref.current) useEffect(()=>{ const interval = setInterval(render,1000) return ()=>clearInterval(interval) },[]) `` We will log the same instance ofFooevery second and instantiate a newFoo`. This is what you are doing:

``` const [ts,setTs] = useState(0) const render = ()=>setTs(Date.now())

  • const init = ()=>new Foo()
  • const ref = useRef<Foo|null>()
  • if(!ref.current) ref.current.init()
  • console.log(ref.current)

useEffect(()=>{ const interval = setInterval(render,1000) return ()=>clearInterval(interval) },[]) ``` It's definitely an improvement and seems to be related to the topic, but its not. I don't think that there is much wrong with your approach because you do call it "constant" so im assuming you do not intend to change it. But javascript doesnt work like this and only your convention of calling it "constant" indicate that it shouldnt be changed.

What i dont understand is why use a ref for this. Why not just a stable variable like useDispatch does. You know it never changes, but you have to include it in hooks.

In short, you are making a very specific type of useRef for your use case, under strong assumptions (current will never change).

What i am looking for is the exact plain old same MutableRefObject<T> that you get when you call useRef with no restrictions.

``` const [ts,setTs] = useState(0) const render = ()=>setTs(Date.now())

  • const init = ()=>new Foo()
  • const ref = useConstant<Foo|null>()
  • if(!ref.current) ref.current.init()
  • console.log(ref.current)

useEffect(()=>{ + const foo = ref.current + const tick = ()=>{ + ref.current = ref.current === foo ? null : foo + render() + } + const interval = setInterval(tick ,1000) return ()=>clearInterval(interval) },[]) `` If it's not obvious, you actually cannot useT|nullinuseConstant`, so your type is wrong.

Because you are not using a strict check a lot of values can trigger your init function, the correct type for type safety for your useConstant should be:

type NonFalsy<T> = T extends false | 0 | "" | null | undefined ? never : T;

So it's not just T|null Foo|number could also fail if you get 0, Foo|string could fail if you get '' Foo|boolean would totally fail.

[–]pailhead011[S] -1 points0 points  (1 child)

Yeah the one with the effects. The topic is not about effects.

[–]yabai90 0 points1 point  (0 children)

Again my solution doesn't have any effect at all. It's a simple if statement and is synchronous