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/contexts/MessengerProvider.tsx b/client/src/contexts/MessengerProvider.tsx
index 51a19fb..c02a1b3 100644
--- a/client/src/contexts/MessengerProvider.tsx
+++ b/client/src/contexts/MessengerProvider.tsx
@@ -16,7 +16,7 @@
* <https://www.gnu.org/licenses/>.
*/
import { ConversationMessage, IConversation, LookupResult, WebSocketMessageType } from 'jami-web-common';
-import { createContext, ReactNode, useContext, useEffect, useState } from 'react';
+import { createContext, ReactNode, useContext, useEffect, useMemo, useState } from 'react';
import { Contact } from '../models/contact';
import { Conversation } from '../models/conversation';
@@ -105,17 +105,16 @@
// return () => controller.abort() // crash on React18
}, [accountId, searchQuery, axiosInstance]);
- return (
- <MessengerContext.Provider
- value={{
- conversations,
- setSearchQuery,
- searchResult,
- newContactId,
- setNewContactId,
- }}
- >
- {children}
- </MessengerContext.Provider>
+ const value = useMemo(
+ () => ({
+ conversations,
+ setSearchQuery,
+ searchResult,
+ newContactId,
+ setNewContactId,
+ }),
+ [conversations, setSearchQuery, searchResult, newContactId, setNewContactId]
);
+
+ return <MessengerContext.Provider value={value}>{children}</MessengerContext.Provider>;
};