saint-bernard
v3.3.0
Published
React Hook for requesting data using the Web API Fetch written in TypeScript
Downloads
15
Maintainers
Readme
saint-bernard
React Hook for requesting data using the Web API Fetch written in TypeScript
Summary
- Features
- Requirements
- Installation
- Uninstallation
- Usage
- Examples
- Changelog
- Code of conduct
- License
- Security
- Contributing
Features
- Close to the metal, configurable yet high-level enough to help you do more with less
- Tested to cover 100% of the source-code published
- Zero-dependencies
- Lightweight
- Written in TypeScript from the ground up
- Strict semantic versionning for the releases
- Best when used with
zod
- Leveraging the Web API Fetch
- Full control over the options, url, path & query parameters
- Ability to cancel requests at any time
- Written to fully work with modern React Hooks and functional components
Requirements
Installation
npm install --save --save-exact saint-bernard
Uninstallation
npm uninstall saint-bernard
Usage
Stateful
state
import React from "react";
import { useStatefulRequest } from "saint-bernard";
export const App = () => {
const { state } = useStatefulRequest<Array<any>>({
initialState: []
});
return (
<ul>
{state.map(user => (
<li key={user.id}>
{user.email}
</li>
))}
</ul>
);
};
setState
import React, { useEffect } from "react";
import { useStatefulRequest } from "saint-bernard";
export const App = () => {
const { setState } = useStatefulRequest<Array<any>>({
initialState: []
});
useEffect(() => {
setState([]);
}, []);
return (
<h1>Saint-Bernard</h1>
);
};
request
import React, { useEffect } from "react";
import { useStatefulRequest } from "saint-bernard";
export const App = () => {
const { request } = useStatefulRequest<Array<any>>({
initialState: []
});
useEffect(() => {
request({
url: "https://jsonplaceholder.typicode.com/posts",
method: "GET",
headers: {
"Accept": "application/json"
},
onResponse: async response => {
const users = await response.json();
return users;
}
});
}, []);
return (
<h1>Saint-Bernard</h1>
);
};
cancel
import React, { useEffect } from "react";
import { useStatefulRequest } from "saint-bernard";
export const App = () => {
const { cancel } = useStatefulRequest<Array<any>>({
initialState: []
});
useEffect(() => {
return () => {
cancel();
};
}, []);
return (
<h1>Saint-Bernard</h1>
);
};
timeout
import React, { useEffect } from "react";
import { useStatefulRequest } from "saint-bernard";
export const App = () => {
const { request } = useStatefulRequest<Array<any>>({
initialState: []
});
useEffect(() => {
request({
url: "https://jsonplaceholder.typicode.com/users",
timeoutInMilliseconds: 1000,
onResponse: async response => {
return [];
}
});
}, []);
return (
<h1>Saint-Bernard</h1>
);
};
error
import React from "react";
import { useStatefulRequest, CancelError } from "saint-bernard";
export const App = () => {
const { error } = useStatefulRequest<Array<any>>({
initialState: []
});
if (error) {
if (error instanceof CancelError) {
return <h1>Request was cancelled</h1>;
}
return <h1>Something went wrong: {error.message}</h1>;
}
return (
<h1>Saint-Bernard</h1>
);
};
setError
import React, { useEffect } from "react";
import { useStatefulRequest } from "saint-bernard";
export const App = () => {
const { setError } = useStatefulRequest<Array<any>>({
initialState: []
});
useEffect(() => {
setError(new Error("Something went wrong"));
}, []);
return (
<h1>Saint-Bernard</h1>
);
};
loading
import React from "react";
import { useStatefulRequest } from "saint-bernard";
export const App = () => {
const { loading } = useStatefulRequest<Array<any>>({
initialState: []
});
if (loading) {
return <h1>Loading...</h1>;
}
return (
<h1>Saint-Bernard</h1>
);
};
initialLoading
import React from "react";
import { request } from "saint-bernard";
export const App = () => {
const { loading } = useStatefulRequest<Array<any>>({
initialState: [],
initialLoading: true
});
if (loading) {
return <h1>Loading...</h1>;
}
return (
<h1>Saint-Bernard</h1>
);
};
setLoading
import React, { useEffect } from "react";
import { useStatefulRequest } from "saint-bernard";
export const App = () => {
const { setLoading } = useStatefulRequest<Array<any>>({
initialState: []
});
useEffect(() => {
setLoading(true);
}, []);
return (
<h1>Saint-Bernard</h1>
);
};
abortController
import React, { useEffect } from "react";
import { useStatefulRequest } from "saint-bernard";
export const App = () => {
const { abortController } = useStatefulRequest<Array<any>>({
initialState: []
});
useEffect(() => {
abortController.abort();
}, []);
return (
<h1>Saint-Bernard</h1>
);
};
setAbortController
import React, { useEffect } from "react";
import { useStatefulRequest } from "saint-bernard";
export const App = () => {
const { setAbortController } = useStatefulRequest<Array<any>>({
initialState: []
});
useEffect(() => {
setAbortController(new AbortController());
}, []);
return (
<h1>Saint-Bernard</h1>
);
};
Stateless
request
import React, { useEffect } from "react";
import { useStatelessRequest } from "saint-bernard";
export const App = () => {
const { request } = useStatelessRequest();
useEffect(() => {
request({
url: "https://jsonplaceholder.typicode.com/posts",
method: "POST",
headers: {
"Accept": "application/json"
},
body: JSON.stringify({
email: "[email protected]"
}),
onResponse: async response => {
if (response.ok) {
console.log("Cool!");
} else {
console.log("Uncool...")
}
}
});
}, []);
return (
<h1>Saint-Bernard</h1>
);
};
cancel
import React, { useEffect } from "react";
import { useStatelessRequest } from "saint-bernard";
export const App = () => {
const { cancel } = useStatelessRequest();
useEffect(() => {
return () => {
cancel();
};
}, []);
return (
<h1>Saint-Bernard</h1>
);
};
timeout
import React, { useEffect } from "react";
import { useStatelessRequest } from "saint-bernard";
export const App = () => {
const { request } = useStatelessRequest();
useEffect(() => {
request({
url: "https://jsonplaceholder.typicode.com/users",
timeoutInMilliseconds: 1000
});
}, []);
return (
<h1>Saint-Bernard</h1>
);
};
error
import React from "react";
import { useStatelessRequest, CancelError } from "saint-bernard";
export const App = () => {
const { error } = useStatelessRequest();
if (error) {
if (error instanceof CancelError) {
return <h1>Request was cancelled</h1>;
}
return <h1>Something went wrong: {error.message}</h1>;
}
return (
<h1>Saint-Bernard</h1>
);
};
setError
import React, { useEffect } from "react";
import { useStatelessRequest } from "saint-bernard";
export const App = () => {
const { setError } = useStatelessRequest();
useEffect(() => {
setError(new Error("Something went wrong"));
}, []);
return (
<h1>Saint-Bernard</h1>
);
};
loading
import React from "react";
import { useStatelessRequest } from "saint-bernard";
export const App = () => {
const { loading } = useStatelessRequest();
if (loading) {
return <h1>Loading...</h1>;
}
return (
<h1>Saint-Bernard</h1>
);
};
initialLoading
import React from "react";
import { useStatelessRequest } from "saint-bernard";
export const App = () => {
const { loading } = useStatelessRequest({
initialLoading: true
});
if (loading) {
return <h1>Loading...</h1>;
}
return (
<h1>Saint-Bernard</h1>
);
};
setLoading
import React, { useEffect } from "react";
import { useStatelessRequest } from "saint-bernard";
export const App = () => {
const { setLoading } = useStatelessRequest();
useEffect(() => {
setLoading(true);
}, []);
return (
<h1>Saint-Bernard</h1>
);
};
abortController
import React, { useEffect } from "react";
import { useStatelessRequest } from "saint-bernard";
export const App = () => {
const { abortController } = useStatelessRequest();
useEffect(() => {
abortController.abort();
}, []);
return (
<h1>Saint-Bernard</h1>
);
};
setAbortController
import React, { useEffect } from "react";
import { useStatelessRequest } from "saint-bernard";
export const App = () => {
const { setAbortController } = useStatelessRequest();
useEffect(() => {
setAbortController(new AbortController());
}, []);
return (
<h1>Saint-Bernard</h1>
);
};
Examples
Dependent requests
import { useEffect } from "react";
import { useStatefulRequest } from "saint-bernard";
import { z } from "zod";
const commentsSchema = z.array(z.object({
postId: z.number()
}));
const postSchema = z.object({
userId: z.number()
});
const userSchema = z.object({
username: z.string()
});
type Comments = z.infer<typeof commentsSchema>;
type Post = z.infer<typeof postSchema>;
type User = z.infer<typeof userSchema>;
export const App = () => {
const {
state: comments,
loading: getCommentsRequestLoading,
error: getCommentsRequestError,
request: getCommentsRequest,
} = useStatefulRequest<Comments | null>({
initialState: null
});
const {
state: post,
request: getPostRequest,
loading: getPostRequestLoading,
error: getPostRequestError
} = useStatefulRequest<Post | null>({
initialState: null
});
const {
state: user,
request: getUserRequest,
loading: getUserRequestLoading,
error: getUserRequestError
} = useStatefulRequest<User | null>({ initialState: null });
useEffect(() => {
getCommentsRequest({
url: "https://jsonplaceholder.typicode.com/comments",
method: "GET",
headers: {
Accept: "application/json"
},
onResponse: async response => {
if (!response.ok) {
throw new Error("Failed requesting comments");
}
const json = await response.json();
const comments = commentsSchema.parse(json);
return comments;
}
});
}, []);
useEffect(() => {
if (!comments) {
return;
}
if (comments.length === 0) {
return;
}
const firstComment = comments[0];
getPostRequest({
url: `https://jsonplaceholder.typicode.com/posts/${firstComment.postId}`,
method: "GET",
headers: {
Accept: "application/json"
},
onResponse: async response => {
if (!response.ok) {
throw new Error("Failed requesting a post");
}
const json = await response.json();
const post = postSchema.parse(json);
return post;
}
});
}, [comments]);
useEffect(() => {
if (!post) {
return;
}
getUserRequest({
url: `https://jsonplaceholder.typicode.com/users/${post.userId}`,
method: "GET",
headers: {
Accept: "application/json"
},
onResponse: async response => {
if (!response.ok) {
throw new Error("Failed requesting a user");
}
const json = await response.json();
const user = userSchema.parse(json);
return user;
}
});
}, [post]);
if (getCommentsRequestLoading) {
return "Requesting comments, please wait...";
}
if (getPostRequestLoading) {
return "Requesting a post, please wait...";
}
if (getUserRequestLoading) {
return "Requesting a user, please wait...";
}
if (getCommentsRequestError) {
return getCommentsRequestError.message;
}
if (getPostRequestError) {
return getPostRequestError.message;
}
if (getUserRequestError) {
return getUserRequestError.message;
}
if (!user) {
return "No user found";
}
return (
<ul>
<li>
Username: {user.username}
</li>
</ul>
);
}
Changelog
See CHANGELOG.md
.
Code of conduct
See CODE_OF_CONDUCT.md
.
License
See LICENSE
.
Security
See SECURITY.md
.
Contributing
See CONTRIBUTING.md
.