diff --git a/lib/utils/keyserver-call.js b/lib/utils/keyserver-call.js
--- a/lib/utils/keyserver-call.js
+++ b/lib/utils/keyserver-call.js
@@ -1,14 +1,22 @@
 // @flow
 
+import _memoize from 'lodash/memoize.js';
 import * as React from 'react';
 import { useDispatch } from 'react-redux';
+import { createSelector } from 'reselect';
 
 import { bindCookieAndUtilsIntoCallServerEndpoint } from './action-utils.js';
-import type { CallServerEndpointOptions } from './call-server-endpoint.js';
+import type { BindServerCallsParams } from './action-utils.js';
+import type {
+  CallServerEndpoint,
+  CallServerEndpointOptions,
+} from './call-server-endpoint.js';
 import { useSelector } from './redux-utils.js';
+import type { PlatformDetails } from '../types/device-types.js';
 import type { Endpoint } from '../types/endpoints.js';
 import type { KeyserverInfo } from '../types/keyserver-types.js';
 import type { Dispatch } from '../types/redux-types.js';
+import type { ConnectionStatus } from '../types/socket-types.js';
 import type { CurrentUserInfo } from '../types/user-types.js';
 
 export type CallKeyserverEndpoint<Args: $ReadOnlyArray<mixed>> = (
@@ -34,74 +42,131 @@
   +config: KeyserverCallConfig<Args>,
 };
 
-export type ExtractAndBindCookieAndUtilsParams<
-  Args: $ReadOnlyArray<mixed>,
-  Return,
-> = {
+// _memoize memoizes the function by caching the result.
+// The first argument of the memoized function is used as the map cache key.
+const baseCreateBoundServerCallsSelector = (
+  // eslint-disable-next-line no-unused-vars
+  keyserverID: string,
+): (BindServerCallsParams => CallServerEndpoint) =>
+  createSelector(
+    (state: BindServerCallsParams) => state.dispatch,
+    (state: BindServerCallsParams) => state.cookie,
+    (state: BindServerCallsParams) => state.urlPrefix,
+    (state: BindServerCallsParams) => state.sessionID,
+    (state: BindServerCallsParams) => state.currentUserInfo,
+    (state: BindServerCallsParams) => state.connectionStatus,
+    (state: BindServerCallsParams) => state.lastCommunicatedPlatformDetails,
+    (
+      dispatch: Dispatch,
+      cookie: ?string,
+      urlPrefix: string,
+      sessionID: ?string,
+      currentUserInfo: ?CurrentUserInfo,
+      connectionStatus: ConnectionStatus,
+      lastCommunicatedPlatformDetails: ?PlatformDetails,
+    ) =>
+      bindCookieAndUtilsIntoCallServerEndpoint({
+        dispatch,
+        cookie,
+        urlPrefix,
+        sessionID,
+        currentUserInfo,
+        connectionStatus,
+        lastCommunicatedPlatformDetails,
+      }),
+  );
+
+type CreateBoundServerCallsSelectorType = (
+  keyserverID: string,
+) => BindServerCallsParams => CallServerEndpoint;
+const createBoundServerCallsSelector: CreateBoundServerCallsSelectorType =
+  (_memoize(baseCreateBoundServerCallsSelector): any);
+
+export type BindKeyserverCallParams = {
   +dispatch: Dispatch,
   +currentUserInfo: ?CurrentUserInfo,
   +keyserverInfos: { +[keyserverID: string]: KeyserverInfo },
-  +keyserverCall: KeyserverCall<Args, Return>,
 };
 
-function getCallKeyserverEndpoint<Args: $ReadOnlyArray<mixed>, Return>(
-  params: ExtractAndBindCookieAndUtilsParams<Args, Return>,
-): CallKeyserverEndpoint<Args> {
-  const { dispatch, keyserverInfos, currentUserInfo, keyserverCall } = params;
-
-  const { config: serverCallConfig } = keyserverCall;
+export type GetCallKeyserverEndpointParams<Args: $ReadOnlyArray<mixed>> = {
+  ...BindKeyserverCallParams,
+  +keyserverCallConfig: KeyserverCallConfig<Args>,
+};
 
-  return (
-    endpoint: Endpoint,
-    data: Object,
-    args: Args,
-    options?: ?CallServerEndpointOptions,
+const bindCallKeyserverEndpointSelector = createSelector(
+  (state: BindKeyserverCallParams) => state.dispatch,
+  (state: BindKeyserverCallParams) => state.currentUserInfo,
+  (state: BindKeyserverCallParams) => state.keyserverInfos,
+  (
+    dispatch: Dispatch,
+    currentUserInfo: ?CurrentUserInfo,
+    keyserverInfos: { +[keyserverID: string]: KeyserverInfo },
   ) => {
-    // TODO
-    if (serverCallConfig.keyserverSelection === 'fanout') {
-      return Promise.resolve(undefined);
-    }
-    const keyserverID = serverCallConfig.keyserverIDExtractor(...args);
-    const {
-      cookie,
-      urlPrefix,
-      sessionID,
-      connection,
-      lastCommunicatedPlatformDetails,
-    } = keyserverInfos[keyserverID];
-
-    const boundCallServerEndpoint = bindCookieAndUtilsIntoCallServerEndpoint({
-      dispatch,
-      currentUserInfo,
-      cookie,
-      urlPrefix,
-      sessionID,
-      connectionStatus: connection.status,
-      lastCommunicatedPlatformDetails,
-    });
-    return boundCallServerEndpoint(endpoint, data, options);
-  };
-}
+    return _memoize(
+      <Args: $ReadOnlyArray<mixed>, Return>(
+        keyserverCall: KeyserverCall<Args, Return>,
+      ): ((...Args) => Promise<Return>) => {
+        const callKeyserverEndpoint = (
+          endpoint: Endpoint,
+          data: Object,
+          args: Args,
+          options?: ?CallServerEndpointOptions,
+        ) => {
+          // TODO
+          if (keyserverCall.config.keyserverSelection === 'fanout') {
+            return Promise.resolve(undefined);
+          }
+          const keyserverID = keyserverCall.config.keyserverIDExtractor(
+            ...args,
+          );
+          const {
+            cookie,
+            urlPrefix,
+            sessionID,
+            connection,
+            lastCommunicatedPlatformDetails,
+          } = keyserverInfos[keyserverID];
+
+          const boundCallServerEndpoint = createBoundServerCallsSelector(
+            keyserverID,
+          )({
+            dispatch,
+            currentUserInfo,
+            cookie,
+            urlPrefix,
+            sessionID,
+            connectionStatus: connection.status,
+            lastCommunicatedPlatformDetails,
+          });
+
+          return boundCallServerEndpoint(endpoint, data, options);
+        };
+
+        return keyserverCall.actionFunc(callKeyserverEndpoint);
+      },
+    );
+  },
+);
 
 function useKeyserverCall<Args: $ReadOnlyArray<mixed>, Return>(
   keyserverCall: KeyserverCall<Args, Return>,
-  paramOverride?: ?$Shape<ExtractAndBindCookieAndUtilsParams<Args, Return>>,
+  paramOverride?: ?$Shape<BindKeyserverCallParams>,
 ): (...Args) => Promise<Return> {
   const dispatch = useDispatch();
   const keyserverInfos = useSelector(
     state => state.keyserverStore.keyserverInfos,
   );
   const currentUserInfo = useSelector(state => state.currentUserInfo);
-  return React.useMemo(() => {
-    const callKeyserverEndpoint = getCallKeyserverEndpoint({
-      dispatch,
-      currentUserInfo,
-      keyserverInfos,
-      keyserverCall,
-      ...paramOverride,
-    });
-    return keyserverCall.actionFunc(callKeyserverEndpoint);
-  }, [dispatch, currentUserInfo, keyserverInfos, keyserverCall, paramOverride]);
+  const bindCallKeyserverEndpointToAction = bindCallKeyserverEndpointSelector({
+    dispatch,
+    keyserverInfos,
+    currentUserInfo,
+    ...paramOverride,
+  });
+  return React.useMemo(
+    () => bindCallKeyserverEndpointToAction(keyserverCall),
+    [bindCallKeyserverEndpointToAction, keyserverCall],
+  );
 }
 
 export { useKeyserverCall };