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/components/ConversationView.tsx b/client/src/components/ConversationView.tsx
index b3deed4..51c0899 100644
--- a/client/src/components/ConversationView.tsx
+++ b/client/src/components/ConversationView.tsx
@@ -21,7 +21,9 @@
 
 import { useAuthContext } from '../contexts/AuthProvider';
 import { CallManagerContext } from '../contexts/CallManagerProvider';
+import { useCallContext } from '../contexts/CallProvider';
 import { useConversationContext } from '../contexts/ConversationProvider';
+import { useWebRtcContext } from '../contexts/WebRtcProvider';
 import { ConversationMember } from '../models/conversation';
 import CallInterface from '../pages/CallInterface';
 import ChatInterface from '../pages/ChatInterface';
@@ -30,9 +32,11 @@
 
 const ConversationView = () => {
   const { conversationId } = useConversationContext();
+  const webRtcContext = useWebRtcContext(true);
+  const callContext = useCallContext(true);
   const { callData } = useContext(CallManagerContext);
 
-  if (callData && callData.conversationId === conversationId) {
+  if (webRtcContext && callContext && callData?.conversationId === conversationId) {
     return <CallInterface />;
   }