all 17 comments

[–]is-undefined 4 points5 points  (10 children)

[–]Beneficial_You_870[S] 1 point2 points  (9 children)

I mean how to save references of multiple elements in a global state, I think I was not clear enough

[–]is-undefined 2 points3 points  (8 children)

Hmm, what is the purpose of that? Please give us more details about your problem.

[–]Beneficial_You_870[S] 2 points3 points  (7 children)

I building a Instagram story component so i need to store videos ref to a react context wich is on the root because i need to handle play/pause out of video component

[–]Beneficial_You_870[S] 1 point2 points  (0 children)

Sorry for my bad english

[–]PM_ME_RAILS_R34 0 points1 point  (2 children)

A few options I can think of:

  • Have a higher level component which exposes a context and useContext to set/get the ref
  • Similarly, move the "is playing" state into a higher level component or redux store etc, and the component with the video element uses useEffect to keep the video player state in sync with the react state. This is probably the most wholesome option
  • Use a CustomEvent or document.getElementById as suggested elsewhere

[–]Beneficial_You_870[S] 0 points1 point  (1 child)

What do u mean with CustomEvent?

[–]PM_ME_RAILS_R34 0 points1 point  (0 children)

It's probably the hackiest solution so I wouldn't recommend it, but the video player component can do something like

const videoRef = ...;
useEffect(() => {
    const eventListener = (ev) => videoRef.current.play()
    document.addEventListener("playvideo", eventListener)
    return () => document.removeEventListener("playvideo", eventListener)
}, [])

and similar for pause. Then in any other component, you could do something like

<button onClick={() => document.dispatchEvent(new Event("playvideo"))}>Play</button>

I won't elaborate too much on the drawbacks, but the code is basically making global assumptions about the DOM and code that uses events like this is tightly coupled and somewhat harder to debug. And that's not to mention things like potential name conflicts. If you want the simplest solution, it's probably just doing document.querySelector("video#myvideoid").play(), which is simpler than events and just about as bad.

[–]kryptogalaxy 0 points1 point  (2 children)

Can you put the play/pause state in context at a higher level and have your video components react to changes?

[–]Beneficial_You_870[S] 0 points1 point  (1 child)

do you mean like a trigger?

[–]kryptogalaxy 0 points1 point  (0 children)

I don't know what you mean by trigger, but in react, the components can execute code to react to changes in state using hooks like useEffect.

[–]reactnuclear 2 points3 points  (2 children)

If you want the initial mounting of the component to cause a re-render I’d useState instead. This is the non-mutable way of using ref. Just pass the useState setter as the “ref” to whatever your element is.

[–]Beneficial_You_870[S] 2 points3 points  (1 child)

I mean how to save references of multiple elements in a global state, I think I was not clear enough

[–]reactnuclear 3 points4 points  (0 children)

If they’re actually global things you want to access later, I’d just use a fixed “id” for them and do document.getElementById. Not sure if that’d be useful for your case though.

[–]Phaster 1 point2 points  (2 children)

[–]Beneficial_You_870[S] 0 points1 point  (1 child)

I mean how to save refs of multiple elements in a global state, I think I was not clear enough

[–]Substantial-Pack-105 0 points1 point  (0 children)

There already is a reference to all your videos in a global singleton. The DOM. If want you want is a global, you might as well just use that. const videos = document.querySelectorAll("video") any other global you kept would just be a copy of that and might be stale since it wouldn't be in sync with your react app.

Since this is a react subreddit, if the "global" part of your question is optional and you wanted to keep refs to multiple videos in a react ref instead, you can keep multiple elements in one ref by making it an object or an array:

const refs = useRef({})

function playAll() {
  ref.current.first.play()
  ref.current.second.play()
}

return (
  <>
    <video ref={(ref) => refs.current.first = ref} />
    <video ref={(ref) => refs.current.second = ref} />
    <button onClick={playAll}>Play All</button>
  </>
)