i want to fetch datas from backend with axios Authorization header.
I get token code from local storage and set it to a state.
for first load every thing is ok and datas are showin correctly.but on each render I got 401 (Unauthorized) error.
here is my code. where is the problem?
const UserManage = () => {
const [tokenCode, setTokenCode] = useState("");
const api_url = "http://localhost:5000";
const accessToken = tokenCode;
const AuthAxios = axios.create({
baseURL: api_url,
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
useEffect(() => {
const loginDetail = JSON.parse(localStorage.getItem("authState"));
setTokenCode(loginDetail.token); //access token code from local storage
}, []);
const [users, setusers] = useState([])
useEffect(() => {
const fetchUsers = async() => {
const {
data
} = await AuthAxios.get(`/user/all`);
setUsers(data);
setUsers(data);
};
try {
fetchUsers();
} catch (error) {
console.log(error);
}
}, []);
}
Related
I am making a small ecommerce and I am using Stripe as a payment method. I got stuck on the request as I get this error:
"You did not provide an API key. You need to provide your API key in the Authorization header, using Bearer auth (e.g. 'Authorization: Bearer YOUR_SECRET_KEY'). See https://stripe.com/docs/api#authentication for details, or we can help at https://support.stripe.com/."
My code:
back:
const router = require("express").Router();
const stripe = require("stripe")(process.env.STRIPE_KEY);
router.post("/payment", (req, res) => {
stripe.charges.create(
{
source: req.body.tokenId,
amount: req.body.amount,
currency: "usd",
},
(stripeErr, stripeRes) => {
if (stripeErr) {
res.status(500).json(stripeErr);
} else {
res.status(200).json(stripeRes);
}
}
);
});
module.exports = router;
Front:
const publicToken = "pk_test..."
const secretKey = "sk_test_..."
const cart = useSelector(state => state.cart)
const navigate = useNavigate();
const [stripeToken, setStripeToken] = useState(null)
const onToken = (token) => {
setStripeToken(token)
}
useEffect(() => {
const makeRequest = async () => {
try{
const res = await userRequest.post("/checkout/payment",{
tokenId: stripeToken.id,
amount: 500,
}, {headers: { 'Authorization': 'Bearer ' + publicToken }})
navigate("/success", {data:res.data})
} catch{}
}
stripeToken && makeRequest();
}, [stripeToken, cart.total, navigate])
I tried to pass the authorization in a thousand ways and I keep getting the same error.
Any suggestions?
Thank you very much.
I have a custom react hook fetching number of comments from an API that looks like this:
export async function useFetchNumberOfComments(articleId) {
const [numberOfComments, setNumbeOfComments] = useState(0);
useEffect(() => {
(async () => {
try {
const response = await axios.get(`https://example.com/${articleId}`, {
headers: {
"Content-Type": "application/json",
"X-API-KEY": "X",
Authorization: localStorage.getItem("access_token"),
},
});
const data = await response.data;
setNumbeOfComments(data);
} catch (err) {
console.log(err);
}
})();
}, []);
return numberOfComments;
}
And I want to use it in a Article component that looks like this:
import { useFetchNumberOfComments } from "../utils";
const SingleArticle = () => {
let { id } = useParams();
// Important state
const [numOfComments, setNumOfComments] = useState(0);
// Not important states
const [title, setTitle] = useState("");
const [author, setAuthor] = useState("");
const [content, setContent] = useState("");
const [comments, setComments] = useState([]);
const [commentAuthor, setCommentAuthor] = useState("");
const [commentContent, setCommentContent] = useState("");
const [imageId, setImageId] = useState("");
const [imageUrl, setImageUrl] = useState("");
const [createdAt, setCreatedAt] = useState();
const postComment = async (e) => {
e.preventDefault();
const dataToSend = {
articleId: id,
author: commentAuthor,
content: commentContent,
};
try {
await axios.post(`https://example.com/comments`, dataToSend, {
headers: {
"Content-Type": "application/json",
"X-API-KEY": "X",
Authorization: localStorage.getItem("access_token"),
},
});
// Here, fetch the number of comments from my custom hook and update numOf Comments in this component
setCommentAuthor("");
setCommentContent("");
} catch (err) {
console.log(err);
}
};
return (
<>
<form onSubmit={postComment}>
// Here are some inputs, labels and a submit button
</form>
<h4 className={styles.h1}>Comments({numOfComments})</h4>
</>
);
};
export default SingleArticle;
Now, the problem is that I have no idea how to do the mentioned activity within the Article component: Once the form data(for comment) are sent, trigger the useFetchNumberOfComments custom hook and set the numOfComments state inside article component to the newly fetched data.
I think you'd be better served refactoring the useFetchNumberOfComments hook to return a fetch function and some fetch request meta data, i.e. loading and response and error states.
Example:
export function useFetchNumberOfComments() {
const [numberOfComments, setNumbeOfComments] = useState(0);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const fetchArticleCommentCount = useCallback(async (articleId) => {
setLoading(true);
try {
const response = await axios.get(`https://example.com/${articleId}`, {
headers: {
"Content-Type": "application/json",
"X-API-KEY": "X",
Authorization: JSON.parse(localStorage.getItem("access_token")),
},
});
const data = await response.data;
setNumbeOfComments(data);
setError(null);
return data;
} catch (err) {
console.log(err);
setError(err);
} finally {
setLoading(false);
}
}, []);
return {
fetchArticleCommentCount,
numberOfComments,
loading,
error
};
};
...
import { useFetchNumberOfComments } from "../utils";
const SingleArticle = () => {
const { id } = useParams();
const {
fetchArticleCommentCount,
numberOfComments,
} = useFetchNumberOfComments();
// Important state
const [numOfComments, setNumOfComments] = useState(0);
// Not important states
...
const postComment = async (e) => {
e.preventDefault();
const dataToSend = {
articleId: id,
author: commentAuthor,
content: commentContent,
};
try {
await axios.post(`https://example.com/comments`, dataToSend, {
headers: {
"Content-Type": "application/json",
"X-API-KEY": "X",
Authorization: localStorage.getItem("access_token"),
},
});
// await returned comment count and update local state
const commentCount = await fetchArticleCommentCount(id);
setNumOfComments(commentCount);
// or use the updated numberOfComments value returned from hook
fetchArticleCommentCount(id);
// both are available, but you only need one or the other here
setCommentAuthor("");
setCommentContent("");
} catch (err) {
console.log(err);
}
};
return (
<>
<form onSubmit={postComment}>
// Here are some inputs, labels and a submit button
</form>
<h4 className={styles.h1}>Comments({numberOfComments})</h4>
</>
);
};
export default SingleArticle;
I have multiple API calls with fairly lengthy, yet similar, response/error handling for each call.
What is the best non-repetitive ways to make multiple independent api calls that update state using fetch?
Copying and pasting 40+ instances of fetch doesn't seem right.
I want to avoid doing this ....
fetch(url,options)
.then((response) => {
// ...
return response.json
})
.then((data) => {
setState(data)
//...
})
.catch((err) => {
//Error logic here
})
Here's what I've done so far:
I made (found and modified) a useFetch hook...
useFetch.ts
//Only calls fetch() when .load() is called.
const useFetch = (path : string, HttpMethod : string, dependencies : any = [] , body : {} | undefined = undefined) => {
const history = useHistory()
const [response, setResponse] = useState<any>({});
const [error, setError] = useState<string>("");
const [isLoading, setIsLoading] = useState<boolean>(false);
const [controller, setController] = useState(2)
const [isReady, setIsReady] = useState<any>(false)
const load = ():void => {
setError("")
//This prevents useEffect from triggering on declaration.
if (isReady) {
//Math.random() is just to get useEffect to trigger.
setController(Math.random())
}
}
const token = localStorage.getItem("token");
let requestOptions:any = {
method: HttpMethod,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "* always",
Authorization: "Token " + token,
},
};
if (body !== undefined) {
requestOptions["body"] = {
body: JSON.stringify(body)
}
}
const URI = BASE_URI + path
useEffect(() => {
const fetchData = async () => {
if (controller !== 2) {
setIsLoading(true);
try {
const res = await fetch(URI, requestOptions);
const json = await res.json();
if (json?.action == "ENFORCE_BILLING" ) {
history.push(BILLING_CREDENTIALS_PATH, { enforceBillingPopUp: true });
}
if (json?.action == "ENFORCE_SMS_CONFIRMATION") {
// Should we log user out, as well?
history.push(CONFIRMATION_CODE_PATH)
}
if (res.ok) {
setResponse(json);
setIsLoading(false)
} else {
setError(json)
setIsLoading(false)
}
} catch (err) {
setError(err);
// Error logic here...
}
}
}
};
fetchData()
setIsReady(true)
}, [controller, ...dependencies]);
return { response, setResponse ,error, isLoading, load, isReady };
};
Component.tsx
//Inside react functional component...
// Prepares to fetch data from back-end
const data1 = useFetch(PATH1, "GET");
const data2 = useFetch(PATH2, "GET");
const data3 = useFetch(PATH3, "GET");
useEffect(() => {
// Initial on load data fetch
// .load() fetches data
data1.load();
data2.load();
data3.load();
}, [activeReservations.isReady]);
// Sort data depending on sort selection
...
Is useFetch considered bad practice? What are the advantages of using Redux, instead?
Any help would be greatly appreciated. Thanks.
I`m new in react, and I get problem with registration:
http.hook.js:17 POST http://localhost:3000/api/auth/register 500 (Internal Server Error)
Error: Что-то пошло не так :(, попробуйте снова
at http.hook.js:21
at async registerHandler (Registration.js:24)
code http.hook.js :
import {useState, useCallback} from 'react';
export const useHttp = () => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const request = useCallback( async (url, method = 'GET', body = null, headers = {}) => {
setLoading(true);
try {
if (body) {
body = JSON.stringify(body);
headers['Content-Type'] = 'application/json'
}
const response = await fetch(url, {method, body, headers});
const data = await response.json();
if (!response.ok) {
throw new Error(data.message || 'Что-то пошло не так :(');
};
setLoading(false);
return data;
} catch (e) {
console.log(e)
setLoading(false);
setError(e.message);
throw e;
}
}, [])
const clearError = useCallback( () => setError(null), []);
return { loading, request, error, clearError }
}
and code Registration.js without front-end:
import React, { useState, useEffect } from 'react';
import { useHttp } from '../hooks/http.hook';
import { useMessage } from '../hooks/message.hook';
export const Registration = () => {
const message = useMessage();
const {loading, error, request, clearError} = useHttp();
const [form, setForm] = useState({
nick: '', email: '', password:''
});
useEffect(() => {
console.log(error);
message(error);
clearError();
}, [error, message, clearError]);
const changeHandler = event => {
setForm({ ...form, [event.target.name]: event.target.value });
};
const registerHandler = async () => {
try {
const data = await request('/api/auth/register', 'POST', {...form});
console.log('Data', data)
} catch (e) {
console.log(e)
}
};
I think the problem with your server-side.
HTTP response code 500 means that the server encountered an unexpected condition.
Test your endpoint by curl or XHR request.
Also maybe you send not valid data.
I'm trying to fetch data from Spotify API. Since I need an access token to do this, I built a custom hook to parse the token from the URL that comes from the server.
I also have another custom hook with the actual request to the API that takes the parsed token as an argument. Both are gathered in a parent hook.
I cannot make this work since the token is never reaching the scope of the request hook so it fails. If I parse the token and make the request within the same hook everything works out just fine. I intended to make a hook for every request since it's not just one, that's why I wanted to pass the token as an argument.
Token custom hook
export default () => {
const [ token, setToken ] = useState('')
useEffect(() => {
const { access_token } = queryString.parse(window.location.search)
return setToken(access_token)
}, [])
return token
}
Request hook
export default function useFetchUserData(token) {
//state
const initialUserState = {
display_name: '',
external_url: '',
images: ''
}
const [ userData, setUserData ] = useState(initialUserState)
const [ isLoading, setIsLoading ] = useState(false)
const [ isError, setIsError ] = useState(false)
useEffect(() => {
async function getUserData() {
setIsLoading(true);
setIsError(false);
const spotify = axios.create({
baseURL: 'https://api.spotify.com/v1/me',
headers: {
'Authorization': `Bearer ${token}`
}
})
try {
const userRes = await spotify('/')
.then( res => { return res.data });
setUserData({
display_name: userRes.display_name,
external_url: userRes.external_urls.spotify,
images: userRes.images[0].url
})
} catch (error) {
setIsError(true)
}
setIsLoading(false);
}
getUserData();
}, [])
const data = {
userData,
isLoading,
isError
}
return data
}
Parent hook
export default function Home() {
const token = useParseToken()
const { userData, isLoading, isError } = useFetchUserData(token);
if (isLoading) return <BarLoader />;
if (isError) return <div>Oops! something went wrong</div>;
return (
<Fragment>
<Header userData={userData}/>
</Fragment>
)
}
What happens in your case is that you are setting a state in useEffect hook in your custom hook to set token. However you return the token from this hook without waiting for the effect to run, so the first time your useFetchUserData hook is called, it will receive empty string as a token. To solve this, you must implement the useFetchUserData hook to run once token is available or it changed
export default function useFetchUserData(token) {
//state
const initialUserState = {
display_name: '',
external_url: '',
images: ''
}
const [ userData, setUserData ] = useState(initialUserState)
const [ isLoading, setIsLoading ] = useState(false)
const [ isError, setIsError ] = useState(false)
useEffect(() => {
async function getUserData() {
setIsLoading(true);
setIsError(false);
const spotify = axios.create({
baseURL: 'https://api.spotify.com/v1/me',
headers: {
'Authorization': `Bearer ${token}`
}
})
try {
const userRes = await spotify('/')
.then( res => { return res.data });
setUserData({
display_name: userRes.display_name,
external_url: userRes.external_urls.spotify,
images: userRes.images[0].url
})
} catch (error) {
setIsError(true)
}
setIsLoading(false);
}
if(token !== '' || token !== null) {
getUserData();
}
}, [token])
const data = {
userData,
isLoading,
isError
}
return data
}
Also since useParseToken returns the token, you don't need to destructure it while using
const token = useParseToken();
You have to use createContext api of react.
Save your token as a context. and use it where ever you want.
I think this repository will help you.