Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update react client tutorial #117

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
134 changes: 48 additions & 86 deletions versioned_docs/version-0.6.2/tutorials/simple-react-app.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ By the end of the tutorial, you'll have a working web application that connects
alt="Finished app"
/>

You can check out the finished project [here](https://github.com/fishjam-dev/fishjam-clients-tutorials/tree/main/FishjamDashboardReact/FishjamDashboard)
You can check out the finished project [here](https://github.com/fishjam-dev/fishjam-clients-tutorials/blob/main/fishjam-react)

## What do you need

Expand All @@ -41,7 +41,7 @@ Firstly create a brand new project.
<TabItem value="vite" label="Vite">

```bash
npm create vite@latest my-react-app -- --template react-ts
npm create vite@latest fishjam-react -- --template react-ts
```

</TabItem>
Expand All @@ -56,7 +56,7 @@ npm create vite@latest my-react-app -- --template react-ts
is necessary to create and connect Fishjam Client.

```bash npm2yarn
npm install https://github.com/fishjam-dev/react-client-sdk#0.1.2
npm install @fishjam-dev/react-client-sdk#0.3.1
```

</TabItem>
Expand All @@ -72,7 +72,7 @@ npm install https://github.com/fishjam-dev/react-client-sdk#0.1.2

## (Optional) Add a bit of CSS styling

For this project, we prepared simple [CSS classes](https://github.com/Crackhoff/fishjam-clients-tutorials/blob/main/FishjamDashboardReact/FishjamDashboard/src/styles.css),
For this project, we prepared simple [CSS classes](https://github.com/fishjam-dev/fishjam-clients-tutorials/blob/main/fishjam-react/src/styles.css),
You are free to use it or create your own.

## General project structure
Expand All @@ -96,17 +96,16 @@ instance. We can do it by using the `create` function from the
sending a track (for example, track name) it has to be serializable as well

```tsx title="App.tsx"
import React from "react";
import { create } from "@fishjam-dev/react-client-sdk";

// Example metadata types for peer and track
// You can define your metadata types just make sure they are serializable
type PeerMetadata = {
name: string;
name: string;
};

type TrackMetadata = {
type: "camera" | "screen";
type: "camera" | "screen";
};

// Create a Fishjam client instance
Expand All @@ -115,7 +114,7 @@ export const {
FishjamContextProvider, // Context provider
} = create<PeerMetadata, TrackMetadata>();

export const App = () => {};
export const App = () => {return (<></>)};
```

### Now we need to wrap our app with the context provider
Expand All @@ -126,12 +125,13 @@ component and wrap the `App` component with the `FishjamContextProvider`:
```tsx title="main.tsx"
import React from "react";
import ReactDOM from "react-dom/client";
import { App, FishjamContextProvider } from "./components/App";
import { App, FishjamContextProvider, } from "./App";
import "./styles.css";

ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
<FishjamContextProvider>
<App />
<App/>
</FishjamContextProvider>
</React.StrictMode>
);
Expand All @@ -144,30 +144,18 @@ that will allow us to enter the peer token and a button that
will connect to the server and join the room. We can also display the status of the connection.

```tsx title="App.tsx"
import React, { useState } from "react";
//...
import { useState } from "react";
//
export const App = () => {
// Create a state to store the peer token
const [token, setToken] = useState("");
return (
<div style={{ display: "flex", flexDirection: "column", gap: "8px" }}>
<input value={token} onChange={(e) => setToken(() => e?.target?.value)} placeholder="token" />
<div style={{ display: "flex", flexDirection: "row", gap: "8px" }}>

<button
disabled={}
onClick={() => {}};
>
Connect
</button>
<button
disabled={}
onClick={() => {}};
>
Disconnect
</button>
<input value={token} onChange={(e) => setToken(() => e?.target?.value)} placeholder="token"/>
<div style={{ display: "flex", flexDirection: "row", gap: "8px" }}>
<button onClick={() => {}}>Connect</button>
<button onClick={() => {}}> Disconnect</button>
<span>Status: {}</span>
</div>
</div>
</div>
);
};
Expand All @@ -176,16 +164,16 @@ export const App = () => {
### Once the UI is ready, we need to implement the logic

```tsx title="App.tsx"
import { SignalingUrl } from "@fishjam-dev/react-client-sdk/.";
//...
//…
export const {
// highlight-start
useStatus, // Hook to check the status of the connection
useConnect, // Hook to connect to the server
useDisconnect, // Hook to disconnect from the server
// highlight-end
FishjamContextProvider, // Context provider
};
} = create<PeerMetadata, TrackMetadata>();

export const App = () => {
// Create a state to store the peer token
const [token, setToken] = useState("");
Expand Down Expand Up @@ -242,44 +230,39 @@ add some logic to send our tracks to the server and receive tracks from others.
This hook uses [Navigator.mediaDevices](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/mediaDevices) take a look how it works

```tsx title="App.tsx"
import React, { useEffect, useState } from "react";
import { create, SCREEN_SHARING_MEDIA_CONSTRAINTS } from "@fishjam-dev/react-client-sdk";
import { SignalingUrl, Peer } from "@fishjam-dev/react-client-sdk/.";
//...
//…
export const {
useStatus, // Hook to check the status of the connection
// highlight-next-line
useApi, // Hook to get the webrtcApi reference
useConnect, // Hook to connect to the server
useDisconnect, // Hook to disconnect from the server
FishjamContextProvider, // Context provider
useClient, // Hook to get the client reference
//…
} = create<PeerMetadata, TrackMetadata>();

export const App = () => {
//...
// Get the webrtcApi reference
const webrtcApi = useApi();

function startScreenSharing() {
// Get screen sharing MediaStream
navigator.mediaDevices.getDisplayMedia(SCREEN_SHARING_MEDIA_CONSTRAINTS).then((screenStream) => {
// Add local MediaStream to webrtc
screenStream.getTracks().forEach((track) => webrtcApi.addTrack(track, screenStream, { type: "screen" }));
};
};
//…
// Get the client reference
const client = useClient();

function startScreenSharing() {
// Get screen sharing MediaStream
navigator.mediaDevices.getDisplayMedia(SCREEN_SHARING_MEDIA_CONSTRAINTS).then((screenStream) => {
// Add local MediaStream to webrtc
screenStream.getTracks().forEach((track) => client.addTrack(track, screenStream, { type: "screen" }));
});
}

return (
//...
//
<button
className="button"
className="button"
disabled={status !== "joined"}
onClick={() => {
startScreenSharing();
}}
>
Start screen share
</button>
<span>Status: {status}</span>
//...
//…
)
};
```
Expand All @@ -297,24 +280,8 @@ For each track received, we will create a new video element and display it on th
Create in your directory file `VideoPlayer.tsx`

```tsx title="VideoPlayer.tsx"
type Props = {
stream: MediaStream | null | undefined;
};

const VideoPlayer = ({ stream }: Props) => {
return (
<div className="video-container">
<video autoPlay playsInline muted ref={/* place for track ref*/} />
</div>
);
};

export default VideoPlayer;
```

### Now the logic for the component

```tsx title="VideoPlayer.tsx"
import { RefObject, useEffect, useRef } from "react";
import "./styles.css";
type Props = {
stream: MediaStream | null | undefined;
};
Expand All @@ -328,7 +295,7 @@ const VideoPlayer = ({ stream }: Props) => {
}, [stream]);

return (
<div>
<div className="video-container">
<video autoPlay playsInline muted ref={videoRef} />
</div>
);
Expand All @@ -340,26 +307,21 @@ export default VideoPlayer;
### Now we can use it in our main component

```tsx title="App.tsx"
import React, { useEffect, useState } from "react";
import { create, SCREEN_SHARING_MEDIA_CONSTRAINTS } from "@fishjam-dev/react-client-sdk";
import { SignalingUrl, Peer } from "@fishjam-dev/react-client-sdk/.";
import VideoPlayer from "./VideoPlayer";
//...
//

export const {
useStatus, // Hook to check the status of the connection
//
// highlight-next-line
useTracks, // Hook to get the tracks from the server
useApi, // Hook to get the webrtcApi reference
useConnect, // Hook to connect to the server
useDisconnect, // Hook to disconnect from the server
FishjamContextProvider, // Context provider
//…
} = create<PeerMetadata, TrackMetadata>();
export const App = () => {
//…
const tracks = useTracks();
//...
<div
style={{
//…
<div style={{
display: "flex",
flexWrap: "wrap",
justifyContent: "center", // To align items in the center
Expand All @@ -370,7 +332,7 @@ export const App = () => {
<VideoPlayer key={trackId} stream={stream} /> // pass the stream to the component
))}
</div>
//...
//
)
```

Expand Down