useDataSource()
import { Dispatch, SetStateAction, useEffect, useState } from "react";
export interface IData<T> {
data: T;
loading: boolean;
loaded: boolean;
setData: Dispatch<SetStateAction<T>>;
updateData: () => any;
}
export function useData<T>(fetchFn: () => Promise<T>, deps: any = []): IData<T> {
const [trigger, setTrigger] = useState<boolean>(false);
const [data, setData] = useState<T>();
const [loading, setLoading] = useState(true);
const [loaded, setLoaded] = useState(false);
useEffect(() => {
async function fetch() {
setLoading(true);
setLoaded(false);
try {
const newData = await fetchFn();
setData(newData);
setLoaded(true);
} catch (e) {
console.error(e);
setData(undefined);
} finally {
setLoading(false);
}
}
fetch();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [...deps, trigger]);
return {
data,
loading,
loaded,
setData,
updateData: () => setTrigger(!trigger)
} as IData<T>;
};
useInterval()
/* eslint-disable react-hooks/exhaustive-deps */
import { useEffect, useState } from "react";
function useInterval(delay: number) {
const [data, setData] = useState<number>(0);
let index = 0;
useEffect(() => {
if (!delay && delay !== 0) { return; }
const id = setInterval(() => setData(index++), delay);
return () => clearInterval(id);
}, [delay]);
return [data, setData];
}
export default useInterval;
useObservable() + useFetch() example
/* eslint-disable react-hooks/exhaustive-deps */
import { useEffect, useState } from "react";
import { Observable } from "rxjs";
import { Select } from "antd";
import { IUser } from "../../domain/user/IUser";
import { appDomain, translate } from "../../domain/wiring/AppDomain";
export function useFetch<T>(fetchFn: () => Promise<T[]>, deps: any[] = []): [T[], Dispatch<SetStateAction<T[]>>] {
const [data, setData] = useState<T[]>([]);
useEffect(() => {
async function fetch() {
const newData = await fetchFn();
setData(newData);
}
fetch();
}, deps);
return [data, setData];
};
interface IProps {
value?: string;
onChange: (value: string) => void;
}
export function UserSelector(props: IProps) {
const company = useObservable(appDomain.ICompanyService.companyObservable());
const [users] = useFetch<IUser>(() => appDomain.IRequestUser.getAllUsersForCompany(company?.id), [company?.id]);
return <Select
showSearch
style={{ minWidth: 200 }}
placeholder={translate("general.select.user")}
optionFilterProp="children"
value={props.value}
onChange={props.onChange}>
{users.map((x: IUser, i: number) => (<Select.Option key={x.id} value={x.id!}>{x.fullName}</Select.Option>))}
</Select>;
}
export function useObservable<T>(subject: Observable<T | undefined>, initialValue?: T): T | undefined {
const [data, setData] = useState<T | undefined>(initialValue);
useEffect(() => {
if (!subject) { return; }
const subscription = subject.subscribe((x: any) => {
setData(x);
});
return () => subscription.unsubscribe();
}, [subject]);
return data;
}
export function useObservableReducer<T>(subject?: Observable<T | undefined>): T | undefined {
const [data, forceUpdate] = useReducer(x => x + 1, 0);
useEffect(() => {
if (!subject) { return; }
const subscription = subject.subscribe(() => {
forceUpdate();
});
return () => subscription.unsubscribe();
}, [subject]);
return data;
}
Old code (with useSubscription)
/* eslint-disable react-hooks/exhaustive-deps */
import { useEffect, useState, Dispatch, SetStateAction } from "react";
import { Subscription } from "rxjs";
import { Select } from "antd";
import { IUser } from "../../domain/user/IUser";
import { appDomain, translate } from "../../domain/wiring/AppDomain";
type ChangeFn<T> = (next: T | undefined) => any;
type SubscribeFn<T> = (nextFn: ChangeFn<T>) => Subscription;
export function useSubscription<T>(subscribeFn: SubscribeFn<T>, deps?: any[]): T | undefined {
const [data, setData] = useState<T | undefined>(undefined);
useEffect(() => {
function onChange(next: T | undefined) {
setData(next);
}
const subscription = subscribeFn(onChange);
return () => subscription.unsubscribe();
}, deps);
return data;
};
export function useDatasource<T>(fetchFn: () => Promise<T[]>, deps: any[]): [T[], Dispatch<SetStateAction<T[]>>] {
const [data, setData] = useState<T[]>([]);
useEffect(() => {
async function fetch() {
const newData = await fetchFn();
setData(newData);
}
fetch();
}, deps);
return [data, setData];
};
/* Example usage */
interface IProps {
value?: string;
onChange: (value: string) => void;
}
export function UserSelector(props: IProps) {
const company = useSubscription(appDomain.ICompanyService.subscribeToCompany.bind(appDomain.ICompanyService));
const [users] = useDatasource<IUser>(() => appDomain.IRequestUser.getAllUsersForCompany(company?.id), [company?.id]);
return <Select
showSearch
style={{ minWidth: 200 }}
placeholder={translate("general.select.user")}
optionFilterProp="children"
value={props.value}
onChange={props.onChange}>
{users.map((x: IUser, i: number) => (<Select.Option key={x.id} value={x.id!}>{x.fullName}</Select.Option>))}
</Select>;
}
687600cookie-checkReact Hooks: Helpers