I'm coding my first react-native program with Axios and found problems making get calls. Sinse it's a Network error I assume the problem is somewhere below.
Api.js:
import axios from "axios";
const api = axios.create({
baseURL: "https://192.168.15.8:3333",
});
export default api;
index.js
async function loadIncidents() {
if (loading) {
return;
}
if (total > 0 && incidents.length === total) {
return;
}
setLoading(true);
try {
const response = await api.get("/incidents", {
params: { page },
});
setIncidents([...incidents, ...response.data]);
setTotal(response.headers["x-total-count"]);
setPage(page + 1);
} catch (err) {
console.log('Ocorreu um erro: ', err)
}
setLoading(false);
}
useEffect(() => {
loadIncidents();
}, []);
you can use try() catch()
async function loadIncidents() {
if (loading) {
return;
}
if (total > 0 && incidents.length === total) {
return;
}
setLoading(true);
let response;
try {
response = await api.get("incidents", {
params: { page },
});
} catch (ex) {
console.log(ex);
}
setIncidents([...incidents, ...response.data]);
setTotal(response.headers["x-total-count"]);
setPage(page + 1);
setLoading(false);
}
Related
Here is my function:
import axios from "axios";
import { redirect } from "react-router-dom";
let fetch = async (data, method, url, responseType, header) => {
let requestObj = { "method": method, "url": url }
if (method.toLowerCase() === "get") {
requestObj.params = data;
} else {
requestObj.data = data;
}
if (responseType) {
requestObj["responseType"] = responseType;
}
if (header) {
requestObj["headers"] = header;
}
axios.interceptors.response.use(
(response) => {
return response;
},
(error) => {
if (error.response.status === 401) {
console.log("Unauthorized");
return redirect("/login");
}else {
return error;
}
}
);
let result = await axios(requestObj);
return result;
}
I want to make this function be called by other components,
Therefore, the useNavigate() solution does not fit my situation.
Is it mean I need to check the response status in each component and forward the browser to the /login when the access is not authorized?
PS: I am using "react-router-dom": "^6.4.2".
import axios from "axios";
import { useNavigate } from "react-router-dom";
let navigate = useNavigate();
let fetch = async (data, method, url, responseType, header) => {
let requestObj = { "method": method, "url": url }
if (method.toLowerCase() === "get") {
requestObj.params = data;
} else {
requestObj.data = data;
}
if (responseType) {
requestObj["responseType"] = responseType;
}
if (header) {
requestObj["headers"] = header;
}
axios.interceptors.response.use(
(response) => {
return response;
},
(error) => {
if (error.response.status === 401) {
console.log("Unauthorized");
return navigate("/login");
}else {
return error;
}
}
);
let result = await axios(requestObj);
return result;
}
try to use useNavigate() instead of redirect this should work
You can use browserHistory to redirect to another component
import { browserHistory } from 'react-router-dom';
if (error.response.status === 401)
{
console.log("Unauthorized");
browserHistory.push('/login');
}
else
{
return error;
}
I'm working with rxdb and I have pull and push handlers for the backend I have used supabase
I have setup the code for replication as follows:
replication.ts
import { RxDatabase } from "rxdb";
import { RxReplicationPullStreamItem } from "rxdb/dist/types/types";
import { replicateRxCollection } from "rxdb/plugins/replication";
import { Subject } from "rxjs";
import { supabaseClient, SUPABASE_URL } from "src/config/supabase";
import { DbTables } from "src/constants/db";
import {
blockPullHandler,
blockPushHandler,
} from "./repilicationhandlers/block";
import { CheckpointType, RxBlockDocument, RxBlocksCollections } from "./types";
export async function startReplication(
database: RxDatabase<RxBlocksCollections>
) {
const pullStream$ = new Subject<
RxReplicationPullStreamItem<RxBlockDocument, CheckpointType>
>();
supabaseClient
.from(DbTables.Block)
.on("*", (payload) => {
console.log("Change received!", payload);
const doc = payload.new;
pullStream$.next({
checkpoint: {
id: doc.id,
updated: doc.updated,
},
documents: [doc] as any,
});
})
.subscribe((status: string) => {
console.log("STATUS changed");
console.dir(status);
if (status === "SUBSCRIBED") {
pullStream$.next("RESYNC");
}
});
const replicationState = await replicateRxCollection({
collection: database.blocks,
replicationIdentifier: "supabase-replication-to-" + SUPABASE_URL,
deletedField: "archived",
pull: {
handler: blockPullHandler as any,
stream$: pullStream$.asObservable(),
batchSize: 10,
},
push: {
batchSize: 1,
handler: blockPushHandler as any,
},
});
replicationState.error$.subscribe((err) => {
console.error("## replicationState.error$:");
console.log(err);
});
return replicationState;
}
blockPullHandler:
export const blockPullHandler = async (
lastCheckpoint: any,
batchSize: number
) => {
const minTimestamp = lastCheckpoint ? lastCheckpoint.updated : 0;
console.log("Pulling data", batchSize, lastCheckpoint);
const { data, error } = await supabaseClient
.from(DbTables.Block)
.select()
.gt("updated", minTimestamp)
.order("updated", { ascending: true })
.limit(batchSize);
if (error) {
console.log(error);
throw error;
}
const docs: Array<Block> = data;
return {
documents: docs,
hasMoreDocuments: false,
checkpoint:
docs.length === 0
? lastCheckpoint
: {
id: lastOfArray(docs).id,
updated: lastOfArray(docs).updated,
},
};
};
blockPushHandler:
export const blockPushHandler = async (
rows: RxReplicationWriteToMasterRow<RxBlockDocumentType>[]
) => {
if (rows.length !== 1) {
throw new Error("# pushHandler(): too many push documents");
}
const row = rows[0];
const oldDoc: any = row.assumedMasterState;
const doc: Block = row.newDocumentState;
console.log(row, oldDoc, doc);
// insert
if (!row.assumedMasterState) {
const { error } = await supabaseClient.from(DbTables.Block).insert([doc]);
console.log("Error 1", error);
if (error) {
// we have an insert conflict
const conflictDocRes: any = await supabaseClient
.from(DbTables.Block)
.select()
.eq("id", doc.id)
.limit(1);
return [conflictDocRes.data[0]];
} else {
return [];
}
}
// update
console.log("pushHandler(): is update");
const { data, error } = await supabaseClient
.from(DbTables.Block)
.update(doc)
.match({
id: doc.id,
replicationRevision: oldDoc.replicationRevision,
});
console.log("Error 2", error);
if (error) {
console.log("pushHandler(): error:");
console.log(error);
console.log(data);
throw error;
}
console.log("update response:");
console.log(data);
if (data.length === 0) {
// we have an updated conflict
const conflictDocRes: any = await supabaseClient
.from(DbTables.Block)
.select()
.eq("id", doc.id)
.limit(1);
return [conflictDocRes.data[0]];
}
return [];
};
But the issue is when I start the application and the pull handler is called correctly but it doesn't stop calling the pull handler and it sends continuous request one after another even after it has fetched the documents even when I set hasMoreDocuments to false It keeps sending requests and running the replicator. Is there something wrong with my configuration?
database.ts:
export const createDatabase = async () => {
const database = await createRxDatabase({
name: "sundaedb",
storage: getRxStorageDexie(),
});
await database.addCollections({
blocks: {
schema: blockSchema as any,
conflictHandler: conflictHandler as any,
},
documents: {
schema: documentSchema as any,
conflictHandler: conflictHandler as any,
},
});
database.blocks.preInsert((docData) => {
docData.replicationRevision = createRevision(
database.hashFunction,
docData as any
);
return docData;
}, false);
database.blocks.preRemove((docData) => {
console.log(" PRE REMOVE !!");
console.log(JSON.stringify(docData, null, 4));
const oldRevHeight = parseRevision(docData.replicationRevision).height;
docData.replicationRevision =
oldRevHeight + 1 + "-" + database.hashFunction(JSON.stringify(docData));
console.log(JSON.stringify(docData, null, 4));
return docData;
}, false);
database.blocks.preSave((docData) => {
const oldRevHeight = parseRevision(docData.replicationRevision).height;
docData.replicationRevision =
oldRevHeight + 1 + "-" + database.hashFunction(JSON.stringify(docData));
return docData;
}, false);
return database;
};
I am using Next.js. I have created an Axios interceptor where a rejected Promise will be returned. But where there is a server-specific error that I need. Next.js is showing the error in the application like this.
And there is the code of the Axios interceptor and instance.
import axios from "axios";
import store from "../redux/store";
import getConfig from 'next/config';
const { publicRuntimeConfig } = getConfig();
let token = "";
if (typeof window !== 'undefined') {
const item = localStorage.getItem('key')
token = item;
}
const axiosInstance = axios.create({
baseURL: publicRuntimeConfig.backendURL,
headers: {
Authorization: token ? `Bearer ${token}` : "",
},
});
axiosInstance.interceptors.request.use(
function (config) {
const { auth } = store.getState();
if (auth.token) {
config.headers.Authorization = `Bearer ${auth.token}`;
}
return config;
},
function (error) {
return Promise.reject(error);
}
);
axiosInstance.interceptors.response.use(
(res) => {
console.log(res)
return res;
},
(error) => {
console.log(error)
return Promise.reject(error);
}
);
export default axiosInstance;
Also, I am using redux and there is the action.
import axios from "../../api/axios";
import { authConstants } from "../types";
export const login = (data) => {
return async (dispatch) => {
try {
dispatch({
type: authConstants.LOGIN_REQUEST,
});
const res = axios.post("/user/login", data);
if (res.status === 200) {
dispatch({
type: authConstants.LOGIN_SUCCESS,
payload: res.data,
});
}
} catch (error) {
console.log(error, authConstants);
dispatch({
type: authConstants.LOGIN_FAILURE,
payload: { error: error.response?.data?.error },
});
}
};
};
Your problem is here...
const res = axios.post("/user/login", data);
You're missing await to wait for the response
const res = await axios.post("/user/login", data);
This fixes two things...
Your code now waits for the response and res.status on the next line will be defined
Any errors thrown by Axios (which surface as rejected promises) will trigger your catch block. Without the await this does not happen and any eventual promise failure bubbles up to the top-level Next.js error handler, resulting in the popup in your screenshot.
I am having a problem that the post request is not sending the updated currentVideo state as setState seems to be nonblocking. How can i make axios wait for the state to be set?
const nextVideo = () => {
if (videoList.indexOf(currentVideo) < videoList.length - 1) {
setCurrentVideo(videoList[videoList.indexOf(currentVideo) + 1]);
setLoading(true);
axios
.post(`${BACK_PORT}/videos/download`, currentVideo)
.then(function (response) {
if (response.data) {
setLoading(false);
} else {
console.log("waiting...");
}
})
.catch(function (error) {
alert(error)
});
} else {
alert("This is the last video");
}
};
Use a variable and store the currentvideo value in it. Then use that variable at both the places,i.e., for setting up the state and making the axios call.
const nextVideo = () => {
if (videoList.indexOf(currentVideo) < videoList.length - 1) {
let currentVideo = videoList[videoList.indexOf(currentVideo) + 1] //change here
setCurrentVideo(currentVideo );
setLoading(true);
axios
.post(`${BACK_PORT}/videos/download`, currentVideo)
.then(function (response) {
if (response.data) {
setLoading(false);
} else {
console.log("waiting...");
}
})
.catch(function (error) {
alert(error)
});
} else {
alert("This is the last video");
}
};
I have a function that successfully makes requests, but am having trouble translating it to the React-Redux data flow because I can't figure out how to return the object that is received in the callback.
What I currently have doesn't work, but I am confident it makes the request successfully because I can see it when I console.log it.
import FBSDK, { AccessToken, GraphRequest, GraphRequestManager } from 'react-native-fbsdk'
export const callback = (error, result) => {
if (error) {
console.log(error);
return error
} else {
console.log(result);
return result;
}
}
export const graphRequestFor = fields => {
AccessToken.getCurrentAccessToken()
.then(token => {
console.log(token);
const request = new GraphRequest(
'/me',
{
accessToken: token.accessToken,
parameters: {
fields: {
string: fields
}
}
}, callback
)
new GraphRequestManager().addRequest(request).start()
})
}
export const login = () => {
graphRequestFor('first_name, last_name')
.then(results => {
return results
}) //undefined
}
Not an answer to my direct question, but a solution to my problem is to make the api call directly inside the action and dispatching the object from the callback
import FBSDK, { AccessToken, GraphRequest, GraphRequestManager } from 'react-native-fbsdk'
export const login = params => dispatch => {
AccessToken.getCurrentAccessToken()
.then(token => {
const request = new GraphRequest(
'/me',
{
accessToken: token.accessToken,
parameters: {
fields: {
string: params
}
}
}, (error, result) => {
if (error) {
console.log(error);
return dispatch(receiveCurrentUser(error))
} else {
return dispatch(receiveCurrentUser(result))
}
}
)
new GraphRequestManager().addRequest(request).start()
})
}