diff --git a/ivette/src/dome/renderer/dome.tsx b/ivette/src/dome/renderer/dome.tsx
index 2b083a73ee982c656767deb4ec20b2d9829b2af2..7468db73e3928db0241cdb377ba98f62febf5c48 100644
--- a/ivette/src/dome/renderer/dome.tsx
+++ b/ivette/src/dome/renderer/dome.tsx
@@ -561,13 +561,12 @@ export function useUpdate(...events: Event<any>[]) {
 
 /**
    Hook to re-render when a Promise returns.
-   The promise will be typically created by using `React.useMemo()`.
    The hook returns three informations:
    - result: the promise result if it succeeds, undefined otherwise;
    - error: the promise error if it fails, undefined otherwise;
    - loading: the promise status, true if the promise is still running.
 */
-export function usePromise<T>(job: Promise<T>) {
+export function usePromiseNoMemo<T> (job: Promise<T>) {
   const [result, setResult] = React.useState<T | undefined>();
   const [error, setError] = React.useState<Error | undefined>();
   const [loading, setLoading] = React.useState(true);
@@ -582,6 +581,45 @@ export function usePromise<T>(job: Promise<T>) {
   return { result, error, loading };
 }
 
+/* Internal type alias */
+type Dependencies = React.DependencyList | undefined
+
+/**
+   Hook to re-render when a Promise returns.
+   The promise construction is memoized.
+   The hook returns three informations:
+   - result: the promise result if it succeeds, undefined otherwise;
+   - error: the promise error if it fails, undefined otherwise;
+   - loading: the promise status, true if the promise is still running.
+*/
+export function usePromise<T> (job: () => Promise<T>, deps: Dependencies) {
+  const memoized = React.useMemo<Promise<T>>(job, deps);
+  return usePromiseNoMemo(memoized);
+}
+
+/* Internal type alias */
+type Serialize<A> = (a: A) => string;
+
+/**
+   Hook to add a cache system to a function, allowing to reuse previous results.
+   As the equality used in JS maps does not allow to effectively implement a
+   cache for complex type, a serialization function can be procured.
+   The hook returns the cached version of the function.
+*/
+export function useCache<K, V>(r: (k: K) => V, s?: Serialize<K>): (k: K) => V {
+  const [ cache ] = React.useState(new Map<string, V>());
+  const serialize = s ?? React.useCallback((k: K) => `${k}`, []);
+  const get = React.useCallback((k: K): V => {
+    const id = serialize(k);
+    if (cache.has(id))
+      return cache.get(id) as V;
+    const v = r(k);
+    cache.set(id, v);
+    return v;
+  }, [ cache, r, s ]);
+  return get;
+}
+
 // --------------------------------------------------------------------------
 // --- Timer Hooks
 // --------------------------------------------------------------------------
diff --git a/ivette/src/dome/renderer/themes.tsx b/ivette/src/dome/renderer/themes.tsx
index fc24cb2bd4ec9f1fea98e3c17a7bde85eb131c3d..924c1bcc8f62d6a153515689b6918ffc31174a6e 100644
--- a/ivette/src/dome/renderer/themes.tsx
+++ b/ivette/src/dome/renderer/themes.tsx
@@ -71,7 +71,7 @@ async function getNativeTheme(): Promise<ColorTheme> {
 
 export function useColorTheme(): [ColorTheme, (upd: ColorSettings) => void] {
   Dome.useUpdate(NativeThemeUpdated);
-  const { result: current } = Dome.usePromise(getNativeTheme());
+  const { result: current } = Dome.usePromiseNoMemo(getNativeTheme());
   const [pref, setTheme] = Settings.useGlobalSettings(ColorThemeSettings);
   return [current ?? jColorTheme(pref), setTheme];
 }
diff --git a/ivette/src/frama-c/kernel/SourceCode.tsx b/ivette/src/frama-c/kernel/SourceCode.tsx
index ee222433767d50953af8b5cbd2388ab532db0633..82569f911589208f66759651514a00776546449e 100644
--- a/ivette/src/frama-c/kernel/SourceCode.tsx
+++ b/ivette/src/frama-c/kernel/SourceCode.tsx
@@ -83,7 +83,7 @@ export default function SourceCode(): JSX.Element {
   const [fontSize] = Settings.useGlobalSettings(Preferences.EditorFontSize);
 
   // Updating the buffer content.
-  const text = React.useMemo(async () => {
+  const { result } = Dome.usePromise(async () => {
     const onError = (): string => {
       if (file)
         D.error(`Fail to load source code file ${file}`);
@@ -91,7 +91,6 @@ export default function SourceCode(): JSX.Element {
     };
     return System.readFile(file).catch(onError);
   }, [file]);
-  const { result } = Dome.usePromise(text);
   React.useEffect(() => buffer.setValue(result), [buffer, result]);
 
   /* Last location selected by a click in the source code. */
diff --git a/ivette/src/frama-c/states.ts b/ivette/src/frama-c/states.ts
index 11b59f05e8aeaacd4265712bb5ad6f52d79cae78..c0d940c7f09c3083b19e9882d26889712d1812cf 100644
--- a/ivette/src/frama-c/states.ts
+++ b/ivette/src/frama-c/states.ts
@@ -788,7 +788,10 @@ export function setSelection(location: Location, meta = false) {
 /** Current selection. */
 export function useSelection(): [Selection, (a: SelectionActions) => void] {
   const [current, setCurrent] = useGlobalState(GlobalSelection);
-  return [current, (action) => setCurrent(reducer(current, action))];
+  const callback = React.useCallback((action) => {
+    setCurrent(reducer(current, action));
+  }, [ current, setCurrent ]);
+  return [current, callback];
 }
 
 /** Resets the selected locations. */