React & Vue
openFetch is a normal JavaScript package: you import it and call .get() / .post() like any other function. It works the same in React, Vue, and other frameworks.
The examples below use a free test API (no API key, no .env file). The URL is written in full so you can copy and run the code as-is.
React
- Install:
npm install @hamdymohamedak/openfetch - Put this in a component file (for example
PostTitle.jsx).
import { useEffect, useState } from "react";
import openFetch from "@hamdymohamedak/openfetch";
export function PostTitle() {
const [title, setTitle] = useState("Loading…");
useEffect(() => {
let active = true;
(async () => {
try {
const res = await openFetch.get(
"https://jsonplaceholder.typicode.com/posts/1"
);
if (active) setTitle(res.data.title);
} catch {
if (active) setTitle("Something went wrong");
}
})();
return () => {
active = false;
};
}, []);
return <p>{title}</p>;
}resis the full response; the JSON body is inres.data.- The
activeflag avoids updating state after the user leaves the page (simple React safety).
When you are ready for a base URL (so you write "/posts/1" instead of the long string), use createClient:
import { createClient } from "@hamdymohamedak/openfetch";
const api = createClient({ baseURL: "https://jsonplaceholder.typicode.com" });
// then: await api.get("/posts/1")Vue 3
- Install:
npm install @hamdymohamedak/openfetch - Use this inside a
.vuefile.
<script setup>
import { onMounted, ref } from "vue";
import openFetch from "@hamdymohamedak/openfetch";
const title = ref("Loading…");
onMounted(async () => {
try {
const res = await openFetch.get(
"https://jsonplaceholder.typicode.com/posts/1"
);
title.value = res.data.title;
} catch {
title.value = "Something went wrong";
}
});
</script>
<template>
<p>{{ title }}</p>
</template>Same idea: res.data holds the parsed JSON. For a shared baseURL, create one client and import it from a small api.js file (see createClient above).
React Server Components (optional)
If your app supports async server components, you can await without useEffect:
import openFetch from "@hamdymohamedak/openfetch";
export default async function Page() {
const res = await openFetch.get(
"https://jsonplaceholder.typicode.com/posts/1"
);
return <p>{res.data.title}</p>;
}With unwrapResponse: true on a createClient used only on the server, the awaited value is the body directly (cleaner JSX):
import { createClient } from "@hamdymohamedak/openfetch";
const api = createClient({
baseURL: "https://jsonplaceholder.typicode.com",
unwrapResponse: true,
});
export default async function Page() {
const post = await api.get("/posts/1");
return <p>{post.title}</p>;
}openFetch does not import React or window; it is safe for typical RSC server bundles as long as your runtime provides fetch.
Cancellation (React / Vue)
Use AbortController and pass signal into the request. On unmount, abort so retries/timeouts stop and state updates can be skipped:
useEffect(() => {
const ac = new AbortController();
let active = true;
(async () => {
try {
const res = await openFetch.get("/posts/1", { signal: ac.signal });
if (active) setTitle(res.data.title);
} catch (e) {
if (!active) return;
// ignore ERR_CANCELED if you aborted on purpose
setTitle("Something went wrong");
}
})();
return () => {
active = false;
ac.abort();
};
}, []);The retry middleware stops when signal aborts (no further attempts; backoff ends early).
Next
- HTTP methods — POST, PUT, DELETE, and more
- Plugins & fluent API — fluent chains and plugins
- Configuration —
baseURL, timeouts, headers - Getting started —
createClientand middleware
