Fix components rerendering unnecessarily
Before, some providers (WebRtcProvider, CallProvider...) were rendered conditionally.
This was causing all their children to re-render when the provider rendered.
Instead of using conditional rendering, these providers now use `ConditionalContextProvider`.
It always renders the provider, but sets its value to `initialValue` if the dependencies are not all defined.
If all dependencies are defined, the value is the result of the `useProviderValue` hook.
Changes:
- New file: `ConditionalContextProvider`
- New file: `HookComponent` - Component that calls a hook when mounted and calls a `callback` function with the hook result as argument
- For `WebRtcProvider` and `CallProvider`, use `createOptionalContext` to create the context and `ConditionalContextProvider` to provide their value only when the conditions are met
- In `WebRtcProvider`, set the webRtcConnection to undefined when not in a call
- For all providers, wrap their `value` prop in `useMemo` to avoid unnecessary rerenders
Change-Id: Ide947e216d54599aabc71cf4bd026bd20d6e0daf
diff --git a/client/src/pages/CallPending.tsx b/client/src/pages/CallPending.tsx
index ea2017d..2ef27f2 100644
--- a/client/src/pages/CallPending.tsx
+++ b/client/src/pages/CallPending.tsx
@@ -17,7 +17,7 @@
*/
import { Box, CircularProgress, Grid, IconButtonProps, Stack, Typography } from '@mui/material';
-import { ComponentType, ReactNode, useContext, useEffect, useMemo, useRef } from 'react';
+import { ComponentType, ReactNode, useEffect, useMemo, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router-dom';
@@ -28,15 +28,15 @@
CallingRefuseButton,
} from '../components/CallButtons';
import ConversationAvatar from '../components/ConversationAvatar';
-import { CallContext, CallStatus } from '../contexts/CallProvider';
+import { CallStatus, useCallContext } from '../contexts/CallProvider';
import { useConversationContext } from '../contexts/ConversationProvider';
-import { WebRtcContext } from '../contexts/WebRtcProvider';
+import { useWebRtcContext } from '../contexts/WebRtcProvider';
import { VideoElementWithSinkId } from '../utils/utils';
export const CallPending = () => {
- const { localStream } = useContext(WebRtcContext);
+ const { localStream } = useWebRtcContext();
const { conversation } = useConversationContext();
- const { callRole } = useContext(CallContext);
+ const { callRole } = useCallContext();
const localVideoRef = useRef<VideoElementWithSinkId | null>(null);
useEffect(() => {
@@ -146,7 +146,7 @@
};
export const CallPendingCallerInterface = () => {
- const { callStatus } = useContext(CallContext);
+ const { callStatus } = useCallContext();
const { t } = useTranslation();
const { conversation } = useConversationContext();
const memberName = useMemo(() => conversation.getFirstMember().contact.registeredName, [conversation]);
@@ -179,7 +179,7 @@
export const CallPendingReceiverInterface = () => {
const { state } = useLocation();
- const { callStatus } = useContext(CallContext);
+ const { callStatus } = useCallContext();
const { t } = useTranslation();
const { conversation } = useConversationContext();