Skip to main content

react-query-usage

For @tramvai/react-query to work, you need to connect the @tramvai/module-react-query module to the application

Basic example with createQuery and useQuery

Expand

import { createQuery, useQuery } from '@tramvai/react-query';
import { FAKE_API_CLIENT } from '../../fakeApiClient';

const query = createQuery({
key: 'base',
async fn(_) {
const { payload } = await this.deps.apiClient.get<string>('api/base');

await new Promise((resolve) => setTimeout(resolve, 50));

return payload;
},
deps: {
apiClient: FAKE_API_CLIENT,
},
});

// eslint-disable-next-line import/no-default-export
export default function Component() {
const { data, isLoading } = useQuery(query);

return <div>{isLoading ? 'loading...' : data}</div>;
}

Preloading data on the server for useQuery

Expand

import { createQuery, useQuery } from '@tramvai/react-query';
import { FAKE_API_CLIENT } from '../../fakeApiClient';

const query = createQuery({
key: 'base',
async fn(_) {
const { payload } = await this.deps.apiClient.get<string>('api/base');
await new Promise((resolve) => setTimeout(resolve, 50));

return payload;
},
deps: {
apiClient: FAKE_API_CLIENT,
},
});

// eslint-disable-next-line import/no-default-export
export default function Component() {
const { data, isLoading } = useQuery(query);

return <div>{isLoading ? 'loading...' : data}</div>;
}

Component.actions = [query.prefetchAction()];

Sharing useQuery data between components

Expand

import { useState, useEffect } from 'react';
import { createQuery, useQuery } from '@tramvai/react-query';
import { FAKE_API_CLIENT } from '../../fakeApiClient';

const query = createQuery({
key: 'base',
async fn(_) {
const { payload } = await this.deps.apiClient.get<string>('api/base');

await new Promise((resolve) => setTimeout(resolve, 5000));

return payload;
},
deps: {
apiClient: FAKE_API_CLIENT,
},
});

const Child1 = () => {
const { isLoading, data } = useQuery(query);

return <div>Child1: {isLoading ? 'loading...' : data}</div>;
};

const Child2 = () => {
const { isLoading, data } = useQuery(query);

return <div>Child2: {isLoading ? 'loading...' : data}</div>;
};

const Child3 = () => {
const { isLoading, data } = useQuery(query);

return <div>Child3: {isLoading ? 'loading...' : data}</div>;
};

// eslint-disable-next-line import/no-default-export
export default function Component() {
const [child2, setChild2Visible] = useState(false);
const [child3, setChild3Visible] = useState(false);

useEffect(() => {
setTimeout(() => {
setChild2Visible(true);
}, 3000);

setTimeout(() => {
setChild3Visible(true);
}, 7000);
}, []);

return (
<>
<Child1 />
{child2 && <Child2 />}
{child3 && <Child3 />}
</>
);
}

Passing parameters for the request

Expand

import { useState, useEffect } from 'react';
import { createQuery, useQuery } from '@tramvai/react-query';
import { FAKE_API_CLIENT } from '../../fakeApiClient';

const query = createQuery({
key: (parameter: string) => ['api-group', parameter],
actionNamePostfix: 'apiGroupQuery',
async fn(parameter) {
console.log(`request to ${parameter}`);
const { payload } = await this.deps.apiClient.get<string>(`api/group/${parameter}`);

await new Promise((resolve) => setTimeout(resolve, 5000));

return payload;
},
deps: {
apiClient: FAKE_API_CLIENT,
},
});

const Child1 = () => {
const { isLoading, data } = useQuery(query, 'test-1');

return <div>Child1: {isLoading ? 'loading...' : data}</div>;
};

const Child2 = () => {
const { isLoading, data } = useQuery(query, 'test-1');

return <div>Child2: {isLoading ? 'loading...' : data}</div>;
};

const Child3 = () => {
const { isLoading, data } = useQuery(query, 'test-2');

return <div>Child3: {isLoading ? 'loading...' : data}</div>;
};
// eslint-disable-next-line import/no-default-export
export default function Component() {
const [child2, setChild2Visible] = useState(false);
const [child3, setChild3Visible] = useState(false);

useEffect(() => {
setTimeout(() => {
setChild2Visible(true);
}, 3000);

setTimeout(() => {
setChild3Visible(true);
}, 7000);
}, []);

return (
<>
<Child1 />
{child2 && <Child2 />}
{child3 && <Child3 />}
</>
);
}

Setting react-query parameters

Expand

import { createQuery, useQuery } from '@tramvai/react-query';
import { FAKE_API_CLIENT } from '../../fakeApiClient';

const query = createQuery({
key: 'time',
async fn(_) {
const { payload } = await this.deps.apiClient.request<string>({
path: 'api/time',
cache: false,
});

return payload;
},
deps: {
apiClient: FAKE_API_CLIENT,
},
queryOptions: {
refetchOnWindowFocus: true,
refetchOnMount: true,
},
});
// eslint-disable-next-line import/no-default-export
export default function Component() {
const { data } = useQuery(
query.fork({
refetchInterval: 2000,
refetchIntervalInBackground: false,
})
);

return <div>{data}</div>;
}

Failed requests

Expand

import { createQuery, useQuery } from '@tramvai/react-query';
import { FAKE_API_CLIENT } from '../../fakeApiClient';

const query = createQuery({
key: 'base',
async fn(_) {
const { payload } = await this.deps.apiClient.get('api/fail');

return payload;
},
deps: {
apiClient: FAKE_API_CLIENT,
},
queryOptions: {
retryDelay: 500,
},
});
// eslint-disable-next-line import/no-default-export
export default function Component() {
const { data, isLoading, isError, error } = useQuery(query);

if (isLoading) {
return <div>loading...</div>;
}

if (isError) {
return <div>error: {error!.message}</div>;
}

return <div>{data}</div>;
}

Using conditions for query

Expand

import { useState, useEffect } from 'react';
import { createQuery, useQuery } from '@tramvai/react-query';
import { FAKE_API_CLIENT } from '../../fakeApiClient';

const query = createQuery({
key: 'auth',
async fn(_) {
const { payload } = await this.deps.apiClient.get('api/auth');

return payload;
},
deps: {
apiClient: FAKE_API_CLIENT,
},
conditions: {
onlyServer: true,
},
});
// eslint-disable-next-line import/no-default-export
export default function Component() {
const { data = 'no-data', isLoading } = useQuery(query);

return <div>{isLoading ? 'loading...' : data}</div>;
}

Basic example for createInfiniteQuery and useInfiniteQuery

Expand

import { createInfiniteQuery, useInfiniteQuery } from '@tramvai/react-query';
import { FAKE_API_CLIENT } from '../../fakeApiClient';

interface Response {
nextPage?: number;
list: string[];
}

const query = createInfiniteQuery({
key: 'list',
async fn(_, start = 0) {
const { payload } = await this.deps.apiClient.get<Response>('api/list', {
query: {
count: 30,
start,
},
});

return payload;
},
getNextPageParam: (page: Response) => {
return page.nextPage;
},
deps: {
apiClient: FAKE_API_CLIENT,
},
infiniteQueryOptions: {},
});

// eslint-disable-next-line import/no-default-export
export default function Component() {
const { data, isLoading, fetchNextPage, hasNextPage } = useInfiniteQuery(query);

if (isLoading) {
return <>loading...</>;
}

return (
<div>
<div>
{data!.pages.map((page) => {
return page.list.map((entry) => {
return <div key={entry}>{entry}</div>;
});
})}
</div>
{hasNextPage && (
<button type="button" onClick={() => fetchNextPage()}>
Load more
</button>
)}
</div>
);
}

Basic example for createMutation and useMutation

Подробнее

import { createMutation, useMutation } from '@tramvai/react-query';
import { FAKE_API_CLIENT } from '../../fakeApiClient';

const mutation = createMutation({
key: 'post',
async fn(_, data: string) {
const { payload } = await this.deps.apiClient.post('api/post', {
body: {
data,
},
});

return payload;
},
deps: {
apiClient: FAKE_API_CLIENT,
},
});
// eslint-disable-next-line import/no-default-export
export default function Component() {
const { isLoading, mutate } = useMutation(mutation);

if (isLoading) {
return <>loading...</>;
}

return (
<button type="button" onClick={() => mutate('test')}>
Send data
</button>
);
}