BIG-126: async localization loaded data failed to be injected to application.

This commit is contained in:
a.bouhuolia
2021-10-06 17:47:52 +02:00
parent 862a667ef6
commit 369734ab18
14 changed files with 192 additions and 136 deletions

View File

@@ -1,27 +1,8 @@
import { isEqual } from 'lodash';
import React, { useRef, useEffect, useMemo } from 'react';
import useAsync from './async';
import { useRef, useEffect, useMemo } from 'react';
import useAutofocus from './useAutofocus';
import { useLocalStorage } from './utils/useLocalStorage';
// import use from 'async';
/**
* A custom useEffect hook that only triggers on updates, not on initial mount
* Idea stolen from: https://stackoverflow.com/a/55075818/1526448
* @param {Function} effect
* @param {Array<any>} dependencies
*/
export function useUpdateEffect(effect, dependencies = []) {
const isInitialMount = useRef(true);
useEffect(() => {
if (isInitialMount.current) {
isInitialMount.current = false;
} else {
effect();
}
}, dependencies);
}
export * from './utils';
export function useIsValuePassed(value, compatatorValue) {
const cache = useRef([value]);
@@ -62,41 +43,7 @@ export function useCellAutoFocus(ref, autoFocus, columnId, rowIndex) {
return ref;
}
export * from './useRequestPdf';
export { useAsync, useAutofocus };
// Hook
export function useLocalStorage(key, initialValue) {
// State to store our value
// Pass initial state function to useState so logic is only executed once
const [storedValue, setStoredValue] = React.useState(() => {
try {
// Get from local storage by key
const item = window.localStorage.getItem(key);
// Parse stored json or if none return initialValue
return item ? JSON.parse(item) : initialValue;
} catch (error) {
return initialValue;
}
});
// Return a wrapped version of useState's setter function that ...
// ... persists the new value to localStorage.
const setValue = (value) => {
try {
// Allow value to be a function so we have same API as useState
const valueToStore =
value instanceof Function ? value(storedValue) : value;
// Save state
setStoredValue(valueToStore);
// Save to local storage
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
// A more advanced implementation would handle the error case
console.log(error);
}
};
return [storedValue, setValue];
}
export { useAutofocus };
export function useMemorizedColumnsWidths(tableName) {
const [get, save] = useLocalStorage(`${tableName}.columns_widths`, {});
@@ -106,42 +53,3 @@ export function useMemorizedColumnsWidths(tableName) {
};
return [get, save, handleColumnResizing];
}
// Hook
function usePrevious(value) {
// The ref object is a generic container whose current property is mutable ...
// ... and can hold any value, similar to an instance property on a class
const ref = useRef();
// Store current value in ref
useEffect(() => {
ref.current = value;
}, [value]); // Only re-run if value changes
// Return previous value (happens before update in useEffect above)
return ref.current;
}
export function useWhen(condition, callback) {
React.useEffect(() => {
if (condition) {
callback();
}
}, [condition, callback]);
}
export function useWhenNot(condition, callback) {
return useWhen(!condition, callback);
}
export function useWatch(state, callback, props) {
const config = { immediate: false, ...props };
const previosuState = usePrevious(state);
const flag = React.useRef(false);
React.useEffect(() => {
if (!isEqual(previosuState, state) || (config.immediate && !flag.current)) {
flag.current = true;
callback(state);
}
}, [previosuState, state, config.immediate, callback]);
}

View File

@@ -1,7 +1,7 @@
import { useQueryClient, useMutation } from 'react-query';
import { useRequestQuery } from '../useQueryRequest';
import useApiRequest from '../useRequest';
import { useRequestPdf } from '../useRequestPdf';
import { useRequestPdf } from '../utils';
import { transformPagination } from 'utils';
import t from './types';

View File

@@ -2,7 +2,7 @@ import { useQueryClient, useMutation } from 'react-query';
import { useRequestQuery } from '../useQueryRequest';
import { transformPagination } from 'utils';
import useApiRequest from '../useRequest';
import { useRequestPdf } from '../useRequestPdf';
import { useRequestPdf } from '../utils';
import t from './types';
// Common invalidate queries.

View File

@@ -1,6 +1,6 @@
import { useQueryClient, useMutation } from 'react-query';
import { useRequestQuery } from '../useQueryRequest';
import { useRequestPdf } from '../useRequestPdf';
import { useRequestPdf } from '../utils';
import useApiRequest from '../useRequest';
import { transformPagination } from 'utils';
import t from './types';

9
src/hooks/utils/index.js Normal file
View File

@@ -0,0 +1,9 @@
export * from './useLocalStorage';
export * from './usePrevious';
export * from './useUpdateEffect';
export * from './useWatch';
export * from './useWhen';
export * from './useRequestPdf';
export * from './useAsync';

View File

@@ -1,6 +1,6 @@
import {useState, useCallback, useEffect} from 'react';
import { useState, useCallback, useEffect } from 'react';
const useAsync = (asyncFunction, immediate = true) => {
export const useAsync = (asyncFunction, immediate = true) => {
const [pending, setPending] = useState(false);
const [value, setValue] = useState(null);
const [error, setError] = useState(null);
@@ -9,16 +9,19 @@ const useAsync = (asyncFunction, immediate = true) => {
// handles setting state for pending, value, and error.
// useCallback ensures the below useEffect is not called
// on every render, but only if asyncFunction changes.
const execute = useCallback((...args) => {
setPending(true);
setValue(null);
setError(null);
const execute = useCallback(
(...args) => {
setPending(true);
setValue(null);
setError(null);
return asyncFunction(...args)
.then(response => setValue(response))
.catch(error => setError(error))
.finally(() => setPending(false));
}, [asyncFunction]);
return asyncFunction(...args)
.then((response) => setValue(response))
.catch((error) => setError(error))
.finally(() => setPending(false));
},
[asyncFunction],
);
// Call execute if we want to fire it right away.
// Otherwise execute can be called later, such as
@@ -31,5 +34,3 @@ const useAsync = (asyncFunction, immediate = true) => {
return { execute, pending, value, error };
};
export default useAsync;

View File

@@ -0,0 +1,34 @@
import React from 'react';
// Hook
export function useLocalStorage(key, initialValue) {
// State to store our value
// Pass initial state function to useState so logic is only executed once
const [storedValue, setStoredValue] = React.useState(() => {
try {
// Get from local storage by key
const item = window.localStorage.getItem(key);
// Parse stored json or if none return initialValue
return item ? JSON.parse(item) : initialValue;
} catch (error) {
return initialValue;
}
});
// Return a wrapped version of useState's setter function that ...
// ... persists the new value to localStorage.
const setValue = (value) => {
try {
// Allow value to be a function so we have same API as useState
const valueToStore =
value instanceof Function ? value(storedValue) : value;
// Save state
setStoredValue(valueToStore);
// Save to local storage
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
// A more advanced implementation would handle the error case
console.log(error);
}
};
return [storedValue, setValue];
}

View File

@@ -0,0 +1,15 @@
import { useRef, useEffect } from 'react';
// Hook
export function usePrevious(value) {
// The ref object is a generic container whose current property is mutable ...
// ... and can hold any value, similar to an instance property on a class
const ref = useRef();
// Store current value in ref
useEffect(() => {
ref.current = value;
}, [value]); // Only re-run if value changes
// Return previous value (happens before update in useEffect above)
return ref.current;
}

View File

@@ -0,0 +1,38 @@
import React from 'react';
import useApiRequest from '../useRequest';
export const useRequestPdf = (url) => {
const apiRequest = useApiRequest();
const [isLoading, setIsLoading] = React.useState(false);
const [isLoaded, setIsLoaded] = React.useState(false);
const [pdfUrl, setPdfUrl] = React.useState('');
const [response, setResponse] = React.useState(null);
React.useEffect(() => {
setIsLoading(true);
apiRequest
.get(url, {
headers: { accept: 'application/pdf' },
responseType: 'blob',
})
.then((response) => {
// Create a Blob from the PDF Stream.
const file = new Blob([response.data], { type: 'application/pdf' });
// Build a URL from the file
const fileURL = URL.createObjectURL(file);
setPdfUrl(fileURL);
setIsLoading(false);
setIsLoaded(true);
setResponse(response);
});
}, []);
return {
isLoading,
isLoaded,
pdfUrl,
response,
};
};

View File

@@ -0,0 +1,19 @@
import { useRef, useEffect } from 'react';
/**
* A custom useEffect hook that only triggers on updates, not on initial mount
* Idea stolen from: https://stackoverflow.com/a/55075818/1526448
* @param {Function} effect
* @param {Array<any>} dependencies
*/
export function useUpdateEffect(effect, dependencies = []) {
const isInitialMount = useRef(true);
useEffect(() => {
if (isInitialMount.current) {
isInitialMount.current = false;
} else {
effect();
}
}, dependencies);
}

View File

@@ -0,0 +1,21 @@
import { useEffect, useRef } from 'react';
export function useWatch(callback, argument) {
const flag = useRef(false);
useEffect(() => {
if (!flag.current) {
flag.current = true;
return;
}
callback(argument);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [argument]);
}
export function useWatchImmediate(callback, argument) {
useEffect(() => {
callback(argument);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [argument]);
}

View File

@@ -0,0 +1,13 @@
import React from 'react';
export function useWhen(condition, callback) {
React.useEffect(() => {
if (condition) {
callback();
}
}, [condition, callback]);
}
export function useWhenNot(condition, callback) {
return useWhen(!condition, callback);
}