useLoad
Load async data. Usually used for network requests. It accepts a callback function as the first parameter, and the callback function must return a promise object. You can use LoadConfig component to set some default options for this hook.
API
type PromiseResolve<T extends Promise<any>> = T extends Promise<infer P>
? P
: never;
type LoadCallback = (...args: any[]) => Promise<any>;
type LoadData<T extends LoadCallback> = PromiseResolve<ReturnType<T>>;
function useLoad<Callback extends LoadCallback>(
callback: Callback,
deps?: React.DependencyList,
options?: {
key?: {};
idle?: boolean | { timeout?: number };
imperative?: boolean;
independent?: boolean;
fallback?: Callback;
initialData?: LoadData<Callback>;
defaultParams?: Parameters<Callback>;
cacheKey?: {};
cacheTime?: number;
staleTime?: number;
cacheValidate?: (data: any) => boolean;
retry?: boolean;
retryLimit?: number;
retryInterval?: number | ((count: number) => number);
fallbackRetry?: boolean;
fallbackRetryLimit?: number;
fallbackRetryInterval?: number | ((count: number) => number);
polling?: boolean;
pollingInterval?: number;
pollingInPageHiding?: boolean;
pollingIntervalInPageHiding?: number;
autoReloadWaitTime?: number;
autoReloadOnPageShow?: boolean;
autoReloadOnWindowFocus?: boolean;
autoReloadOnNetworkReconnect?: boolean;
onSuccess?: (data: LoadData<Callback>) => void;
onFailure?: (error: any) => void;
onFinally?: () => void;
}
): {
data: LoadData<Callback> | undefined;
error: any;
loading: boolean;
reloading: boolean;
initializing: boolean;
load: (...params: Parameters<Callback>) => ReturnType<Callback>;
force: (...params: Parameters<Callback>) => ReturnType<Callback>;
reload: (options?: { force?: boolean }) => void;
cancel: () => void;
update: (
newData:
| LoadData<Callback>
| ((prevData?: LoadData<Callback>) => LoadData<Callback>)
) => void;
};
Params:
callback: A function returns a promise object. It is automatically called after the component is mounted by default.deps: Auto reload dependency list. Default is an empty array. It's not working when theimperativeoption istrue.options: Options object.options.key: An identifier that can be any data type exceptnullandundefined. By default, if multiple requests for the same key appear on the page, only first one request will be sent, and other requests will get data by listening to internal events. You can prevent the default behavior by setting theindependentoption totrue. Another function of thekeyoption is that it can be used withuseReloadhook.options.idle: Run callback during the browser's idle periods. You can set an object contains atimeoutproperty to limit the max waiting time.options.imperative: Run callback manually by calling theloadorforcefunction, rather than automatically after the component is mounted.options.independent: Set this option toture, event if thekeyare the same, request callbacks in the page are independent and all of them will be executed.options.fallback: When thecallbackfunction reject an error and the count of retries has been exhausted, thefallbackfunction will be called.options.initialData: Initial data. Used when no cache or request is loading.options.defaultParams: The default parameter array set forcallbackandfallback.options.cacheKey: Cache key to enable caching. It can be any type exceptnullandundefined. This hook uses the same cache instance asuseCache, so you can useuseCachehook to get data cached by this hook, or set cache data for this hook.options.cacheTime: Cache time, in milliseconds. Default is 5 minutes. You can set a permanent cache by setting this option greater than or equal toNumber.MAX_SAFE_INTEGER, for exampleInfinity.options.staleTime: Stale time, in milliseconds. Default is0. It must be used withcacheKey. In thestaleTimeperiod, the data is considered fresh. Callingload(...params),reload()or auto reloading has no effect. You can ignore thestaleTimeoption by callingforce(...params)orreload({ force: true })methods.options.cacheValidate: Validate the cache value. If it returns falsy, theinitialDatawill be used.options.retry: Enable retry callback. Default isfalse.options.retryLimit: Callback retry limit. Default is3.options.retryInterval: Callback retry interval. Default is0. You can set a function that returns a number value for this option, for example(count) => Math.pow(2, count).options.fallbackRetry: Enable retry fallback. Default isfalse.options.fallbackRetryLimit: Fallback retry limit. Default is3.options.fallbackRetryInterval: Fallback retry interval. It also can be a function.options.polling: Enable polling when page visible. Default isfalse.options.pollingInterval: Polling internal when page visible, in milliseconds. Default is30000.options.pollingInPageHiding: Enable polling when page hidden. Default isfalse. This option is not associated withpollingoption.options.pollingIntervalInPageHiding: Polling internal when page hidden, in milliseconds. Default is60000.options.autoReloadWaitTime: Throttle wait time on auto reload, in milliseconds. Default is10000.options.autoReloadOnPageShow: Enable auto reload on page show. Default isfalse.options.autoReloadOnWindowFocus: Enable auto reload on window focus. Default isfalse.options.autoReloadOnNetworkReconnect: Enable auto reload on network reconnect. Default isfalse.options.onSuccess: Success event.options.onFailure: Failure event.options.onFinally: Finally event.
Results:
data: Resolved data. Initial value isundefinedwhen theinitialDatais not specified.error: Rejected error. Initial value isnull.loading: Loading state. Initial value is opposite to theimperativeoption.reloading: Equal toloading && data !== undefined. Provided for convenience.initializing: Equal toloading && data === undefined. Provided for convenience.load: Load function. Used in the same way as thecallback.force: Similar toloadfunction, but it ignores thestaleTimeoption.reload: Reload function. When theforceoption is set totrue, thestaleTimeoption will be ignored.cancel: Cancel everything, including executing request, polling, automatic loading, etc.update: Update thedata.
Examples
Basic
Loading...
import React from "react";
import { useLoad } from "@lilib/hooks";
const getData = () => {
return new Promise<string>((resolve, reject) => {
setTimeout(() => {
if (Math.random() >= 0.5) {
resolve("@lilib/hooks");
} else {
reject(new Error("rejected"));
}
}, 1000);
});
};
function Example() {
const { data, error, loading } = useLoad(getData);
if (error) {
return <div>Error: {error.message}</div>;
}
if (loading) {
return <div>Loading...</div>;
}
return <div>Data: {data}</div>;
}
export default Example;
Dependency list
Count: Loading...
import React, { useState } from "react";
import { useLoad } from "@lilib/hooks";
function Example() {
const [count, setCount] = useState(0);
const { data, loading } = useLoad(() => {
return new Promise<number>((resolve) => {
setTimeout(() => {
resolve(count);
}, 1000);
});
}, [count]);
return (
<div>
<button onClick={() => setCount(count + 1)}>Increase</button>
Count: {loading ? "Loading..." : data}
</div>
);
}
export default Example;
Imperative (Manual)
Number: undefined
import React from "react";
import { useLoad } from "@lilib/hooks";
const getNumber = () => {
return new Promise<number>((resolve) => {
setTimeout(() => {
resolve(Math.random());
}, 1000);
});
};
function Example() {
const { data, loading, load } = useLoad(getNumber, [], { imperative: true });
return (
<div>
<button onClick={() => load()}>Load</button>
Number: {loading ? "Loading..." : String(data)}
</div>
);
}
export default Example;
Load key
Number: Loading...
Number: Loading...
import React from "react";
import { useLoad, useReload } from "@lilib/hooks";
const getNumber = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(Math.random());
}, 1000);
});
};
function Component() {
const { data, loading, reload } = useLoad(getNumber, [], { key: "load-key" });
return (
<div>
Number: {loading ? "Loading..." : data}
<button onClick={() => reload()}>Reload</button>
</div>
);
}
function Example() {
const reload = useReload("load-key");
return (
<>
<Component />
<Component />
<button onClick={() => reload()}>Reload</button>
</>
);
}
export default Example;
Independent
Number: Loading...
Number: Loading...
import React from "react";
import { useLoad, useReload } from "@lilib/hooks";
const getNumber = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(Math.random());
}, 1000);
});
};
function Component() {
const { data, loading, reload } = useLoad(getNumber, [], {
key: "load-independent",
independent: true,
});
return (
<div>
Number: {loading ? "Loading..." : data}
<button onClick={() => reload()}>Reload</button>
</div>
);
}
function Example() {
const reload = useReload("load-independent");
return (
<>
<Component />
<Component />
<button onClick={() => reload()}>Reload</button>
</>
);
}
export default Example;
Load params
Count: -1 (Loading...)
import React, { useRef } from "react";
import { useLoad } from "@lilib/hooks";
const getCount = (count: number) => {
return new Promise<number>((resolve) => {
setTimeout(() => {
resolve(count);
}, 1000);
});
};
function Example() {
const countRef = useRef(0);
const { data, loading, load } = useLoad(getCount, [], {
initialData: -1,
defaultParams: [0],
});
return (
<div>
<button onClick={() => load(++countRef.current)}>Load</button>
Count: {data} {loading ? "(Loading...)" : ""}
</div>
);
}
export default Example;
Fallback
Loading...
import React from "react";
import { useLoad } from "@lilib/hooks";
const getNumberError = () => {
return new Promise<number>((resolve, reject) => {
setTimeout(() => {
reject(new Error("rejected"));
}, 1000);
});
};
const getNumberFallback = () => {
return new Promise<number>((resolve) => {
setTimeout(() => {
resolve(Math.random());
}, 1000);
});
};
function Example() {
const { data, error, loading } = useLoad(getNumberError, [], {
fallback: getNumberFallback,
});
if (error) {
return <div>Error: {error.message}</div>;
}
if (loading) {
return <div>Loading...</div>;
}
return <div>Number: {data}</div>;
}
export default Example;
Caching
import React from "react";
import { useLoad, useToggle } from "@lilib/hooks";
const getNumber = () => {
return new Promise<number>((resolve) => {
setTimeout(() => {
resolve(Math.random());
}, 1000);
});
};
function Component() {
const { data, loading } = useLoad(getNumber, [], {
cacheKey: "load-cache-key",
});
return (
<div>
Number: {String(data)} {loading ? "(Loading...)" : ""}
</div>
);
}
function Example() {
const [visible, { toggle }] = useToggle(false);
return (
<div>
<button onClick={() => toggle()}>{visible ? "Hide" : "Show"}</button>
{visible && <Component />}
</div>
);
}
export default Example;
Stale time
staleTime must be used with cacheKey.
Number: undefined
import React from "react";
import { useLoad } from "@lilib/hooks";
const getNumber = () => {
return new Promise<number>((resolve) => {
setTimeout(() => {
resolve(Math.random());
}, 1000);
});
};
function Example() {
const { data, loading, load, force } = useLoad(getNumber, [], {
imperative: true,
cacheKey: "load-stale-time",
staleTime: 5000,
});
return (
<div>
<button onClick={() => load()}>Load</button>
<button onClick={() => force()}>Force</button>
Number: {loading ? "Loading..." : String(data)}
</div>
);
}
export default Example;
Retries
import React from "react";
import { useLoad } from "@lilib/hooks";
const getNumber = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() >= 0.8) {
resolve("resolved");
} else {
reject(new Error("rejected"));
}
}, 1000);
});
};
const getNumberFallback = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() >= 0.8) {
resolve("fallback resolved");
} else {
reject(new Error("fallback rejected"));
}
}, 1000);
});
};
function Example() {
const { data, error, loading, load } = useLoad(getNumber, [], {
imperative: true,
fallback: getNumberFallback,
retry: true,
fallbackRetry: true,
});
return (
<div>
<button onClick={() => load()}>Load</button>
{loading ? "loading" : error ? error.message : data}
</div>
);
}
export default Example;
Polling
Count:
import React from "react";
import { useLoad } from "@lilib/hooks";
let count = 0;
const getCount = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(++count);
}, 1000);
});
};
function Example() {
const { data, loading, load, cancel } = useLoad(getCount, [], {
imperative: true,
polling: true,
pollingInterval: 3000,
});
return (
<div>
<button onClick={() => load()}>Start</button>
<button onClick={() => cancel()}>Cancel</button>
Count: {data} {loading ? "(Loading...)" : ""}
</div>
);
}
export default Example;
Auto reload
Count: (Loading...)
import React from "react";
import { useLoad } from "@lilib/hooks";
let count = 0;
const getCount = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(++count);
}, 1000);
});
};
function Example() {
const { data, loading } = useLoad(getCount, [], {
autoReloadOnPageShow: true,
autoReloadOnWindowFocus: true,
autoReloadOnNetworkReconnect: true,
});
return (
<div>
Count: {data} {loading ? "(Loading...)" : ""}
</div>
);
}
export default Example;
Events
import React from "react";
import { useLoad } from "@lilib/hooks";
const getData = () => {
return new Promise<string>((resolve, reject) => {
setTimeout(() => {
if (Math.random() >= 0.5) {
resolve("resolved");
} else {
reject(new Error("rejected"));
}
}, 1000);
});
};
function Example() {
const { load } = useLoad(getData, [], {
imperative: true,
onSuccess: () => {
console.log("onSuccess");
},
onFailure: () => {
console.log("onFailure");
},
onFinally: () => {
console.log("onFinally");
},
});
function handleClick() {
load()
.then(() => {
console.log("success");
})
.catch(() => {
console.log("failed");
});
}
return <button onClick={handleClick}>Load</button>;
}
export default Example;
Prefetch
Number:
import React from "react";
import { useLoad } from "@lilib/hooks";
const getNumber = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(Math.random());
}, 1000);
});
};
function RequestInBackground() {
useLoad(getNumber, [], {
idle: true,
cacheKey: "load-prefetch",
cacheTime: Infinity,
});
return null;
}
function Example() {
const { data, loading, load } = useLoad(getNumber, [], {
imperative: true,
cacheKey: "load-prefetch",
staleTime: Infinity,
});
return (
<>
<RequestInBackground />
<button onClick={() => load()}>Load</button>
Number: {data} {loading ? "(Loading...)" : ""}
</>
);
}
export default Example;
Infinite list
import React, { useState } from "react";
import { useLoad } from "@lilib/hooks";
let count = 0;
const getCount = () => {
return new Promise<number>((resolve) => {
setTimeout(() => {
resolve(++count);
}, 1000);
});
};
function Example() {
const [list, setList] = useState<number[]>([]);
const { loading, load } = useLoad(getCount, [], {
imperative: true,
onSuccess: (count) => {
setList((list) => [...list, count]);
},
});
return (
<div>
<button onClick={() => load()}>Load</button>
<ul>
{list.map((item) => (
<li key={item}>{item}</li>
))}
{loading && <li key="loading">Loading...</li>}
</ul>
</div>
);
}
export default Example;