React Server Components and navigator

122 views Asked by At

For context, my project uses the latest Next.js which uses App Router, client components, and server components.

I am trying to use await navigator.mediaDevices.getUserMedia in one of my server components but it does not work since I believe navigator is a Web API and the component is being rendered on the server. I think this is the case since navigator.mediaDevices.getUserMedia works in a client component. I have to use a server component here since async is not allowed for client components.

I cannot figure out a good way to go about this. Is there a good workaround for this?

For example my code so far:

export default async function Recorder({}: Props) {
    let stream = await navigator.mediaDevices.getUserMedia({
        video: true,
        audio: true,
    });
    return <h1></h1>;
1

There are 1 answers

0
Sandip Jaiswal On

There are two ways to solve the problem but before that Let's understand few important topic about SSR. We are focusing on SSR mainly to provide a first user experience because we render html on server which doesn't need any JS on browser to paint the HTML. Which gives a really good experience to first time user. But do we always need to render the full HTML on server. And the answer is it's all depends on requirement and sometimes a part of HTML, we can defer and usually we defer. Let's come to the answer.

First way is to get the user agent from the browser and map with a prebuilt json for the browser with version supporting required feature.

Second way is to use client component which is new feature of ReactJs and supports in NextJs. You can rewrite this component in following way:

export default function Recorder({}: Props) {
    const [stream, setStream] = useState<MediaStream>(null);
    useEffect(() => {
      navigator.mediaDevices.getUserMedia({
        video: true,
        audio: true,
      }).then(mediaStream => {
        if (stream) {
          setStream(mediaStream);
        }
      });

    }, [])
    
    return <h1></h1>;
  }

If you are using a version which doesn't support this type of client component then there is another way to ensure component will render on client only