export interface IUseDataState<T> {
data: T | undefined;
trigger: number;
revision: number;
loading: boolean;
loaded: boolean;
initialLoading: boolean;
}
export function useData<T>(fetchFn: () => Promise<T>, deps: any = []): IData<T> {
const [state, setState] = useObjectState<IUseDataState<T>>({
revision: 0,
trigger: 0,
loaded: false,
loading: true,
initialLoading: true,
data: undefined
});
useEffectAsync(async () => {
if (!state.initialLoading) {
setState({ loading: true, loaded: false });
}
let newState: Partial<IUseDataState<T>> = {};
try {
const newData = await fetchFn();
newState = { data: newData, loaded: true, revision: state.revision + 1 };
} catch (e) {
console.error(e);
newState = { data: undefined, revision: state.revision + 1 };
} finally {
setState({ ...newState, loading: false, initialLoading: false });
}
}, [...deps, state.trigger]);
return {
data: state.data,
revision: state.revision,
loading: state.loading,
loaded: state.loaded,
initialLoading: state.initialLoading,
setData: (data: T) => setState({ data: data, revision: state.revision + 1 }),
updateData: () => setState({ trigger: state.trigger + 1 })
} as IData<T>;
}Example component:
export function UserInfo(props: { userId: string }): React.ReactElement {
const ds = useData(() => appDomain.IUserService.loadUser(props.userId), [props.userId]);
const user = ds.data;
return <div>
Loading: {ds.loading}
User name: {user?.name}
<button type="button" onClick={ds.updateData}>Refresh</button>
</div>;
}
782700cookie-checkReact Hook: useData()