i'M working on a Chat Application project
but im getting this error of fetching friends from the backend(node)
I'm getting the friends data on the console but i'm unable to display it.
this is my Context and States
export const Messenger = () => {
// Context State
const { friends, setFriends, authInfo } = useAuth();
const [loggedUser, setLoggedUser] = useState();
const { updateNotification } = useNotification();
const fetchMessengerUsers = async () => {
try {
const token = getToken();
const config = {
headers: {
authorization: "Bearer " + token,
},
};
const { data } = await client("/get-friends", config);
console.log(data);
setFriends(data);
} catch (error) {
updateNotification("error", "Failed To load the Chat");
}
};
useEffect(() => {
setLoggedUser(localStorage.getItem("auth-token"));
fetchMessengerUsers();
}, []);
then in return i'm mapping all friends to display them
<div className="friends">
{friends && friends.length > 0
? friends.map((fd) => (
<div className="hover-friend">
<Friends friend={fd} />
</div>
))
: "No Friend"}
</div>
It displays No Friend on the browser
this link shows how it appears on the browser
just change your fetchMessengerUsers function.
you need to set setFriends(data.friends)
const fetchMessengerUsers = async () => {
try {
const token = getToken();
const config = {
headers: {
authorization: "Bearer " + token,
},
};
const { data } = await client("/get-friends", config);
console.log(data);
setFriends(data.friends); // you have to set friends array here, earlier you were setting the entire object.
} catch (error) {
updateNotification("error", "Failed To load the Chat");
}
};
Related
I am stuck and looking for someone to help me. I've been trying to Authorize my fetch request but it always return an error. Is there someone who could explain in what way authorize header?
import { ref } from "vue";
const getAllData = () => {
const data = ref();
const entry = "user:pass";
const fetchAllData = async function () {
const res = await fetch("http://127.0.0.1:8000/articles/", {
method: "GET",
headers: {
// How to authorize?
Authorization: Bearer ${entry},
},
});
data.value = await res.json();
console.log(data.value);
};
return { data, fetchAllData };
};
export default getAllData;
I have the following function in my ReactJS app:
function MyView() {
const [mydata, setMyData] = useState({ mydata: {} });
const [mystatus, setMyStatus] = useState({ mystatus: null });
useEffect(() => {
let config = {
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('my-token'),
'Content-Type': 'application/json'
}
}
const fetchData = async () => {
const result = await axios(
'http://localhost:8000/endpoint/' + some_id + "/",
config
);
setMyStatus(result.status);
setMyData(result.data);
};
fetchData();
}, []);
.... <Loading the rest of functions and HTML here>
I want to make sure that the mystatus is 200 and that mydata.view == public before I load anything here. The problem is that JS loads rest of the page before the response is received from server.
How do I stop it from doing that i.e, redirect to another page if mystatus !== 200 or mydata.view !== 'public'
You can conditionally render the react component based on the value of the components states mystatus and mydata.
const [mydata, setMyData] = useState(null);
const [mystatus, setMyStatus] = useState(null);
const history = useHistory();
useEffect(() => {
let config = {
headers: {
Authorization: 'Bearer ' + localStorage.getItem('my-token'),
'Content-Type': 'application/json',
},
};
const fetchData = async () => {
const result = await axios(
'http://localhost:8000/endpoint/' + some_id + '/',
config
);
setMyStatus(result.status);
setMyData(result.data);
};
fetchData();
}, []);
if (!mystatus || !mydata) {
return <h1>Loading....</h1>;
}
if (
(mystatus?.status !== 200) ||
(mydata?.view !== 'public')
) {
history.push('/redirect-to-your-public-route');
}
// .... <Loading the rest of functions and HTML here>
You can't stop loading, instead return null until mystatus and mydata.view will satisfy the condition.
function MyView() {
const [mydata, setMyData] = useState();
const [mystatus, setMyStatus] = useState();
const [loading, setLoading] = useState(true);
useEffect(() => {
let config = {
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('my-token'),
'Content-Type': 'application/json'
}
}
const fetchData = async () => {
const result = await axios(
'http://localhost:8000/endpoint/' + some_id + "/",
config
);
if (result.status !== 200 || result.data.myview !== "public") {
window.location.href = "your_redirect_url"
}
setMyStatus(result.status);
setMyData(result.data);
setLoading(false);
};
fetchData();
}, []);
if (loading) {
return <>Loading...</>
}
if (mystatus !== 200 || mydata.myview !== "public") {
return null;
}
return // rest of your code
}
You can't at the moment, even if there is a way it will be kind of hacky.
Instead, you can consider rendering a placeholder/skeleton first similar to this:
Then, when the data is ready and verified, you replace the placeholder/skeleton with actual content.
As for error handling, you can do something like this:
const fetchData = async () => {
try {
const result = await axios(
'http://localhost:8000/endpoint/' + some_id + "/",
config
);
setMyStatus(result.status);
setMyData(result.data);
} catch (error) {
// do something
// redirect to the corresponding page
}
};
Note, the upcoming concurrent mode (still experimental and have no ETA, but this has been discussed for a long time) will change the practice diastically.
You can have a boolean stating if it can show page or not and only show if that is true.
const [canShow, setCanShow] = useState(false);
Then set it to true if all the requirements are met.
const fetchData = async () => {
const result = await axios(
'http://localhost:8000/endpoint/' + some_id + "/",
config
);
if(result.status === 200 && result.data.view === "public")
setCanShow(true)
setMyData(result.data);
};
Then in the return of your function have a check to see if you show the page or a loading screen or whatever you want.
return(
{canShow ? /* display whatever page it should show */ : /* show loading page or whatever else */}
}
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 have the following react js code page:
import React, { useState } from "react";
import { Auth, API } from "aws-amplify";
function dailyFiles(props) {
const [apiError502, setApiError502] = useState(false);
// Pull out into a generic reusable function
const getData = async () => {
try {
let apiName = "Dev";
let path = "/test";
let myInit = {
headers: {
Authorization: `Bearer ${(await Auth.currentSession())
.getIdToken()
.getJwtToken()}`
}
};
var result = await API.get(apiName, path, myInit);
} catch (e) {
if (e.message === "Request failed with status code 502") {
toggleApiError502(true);
} else {
alert(JSON.stringify(e));
props.onLogout();
}
}
return result;
};
const toggleApiError502 = (show = false) => {
setApiError502(show);
};
var files = {
Files: [
{
Day: "Monday",
file: "10-02-2020"
},
{
Day: "Friday",
file: "14-02-2020"
}
]
};
return (
<div className="animated fadeIn">
<div>
{files.Files.map(block => block.Day + ": " + block.file + " ")}
</div>
</div>
);
}
export default dailyFiles;
When I call from my div the static Var files variable:
var files = {Files: [{Day: "Monday",file: "10-02-2020"},{Day: "Friday",file: "14-02-2020"}]};
<div>
{files.Files.map(block => block.Day + ": " + block.file + " ")}
</div>
I got the expected result, but how can I get the same result calling my function getData()?
const getData = async () => {
getData function call an API which return the same content result as var files has?
I've tried to call the function with this.getdata() within the div but not successful result.
Use useEffect to get the data after the component has mounted.
function dailyFiles(props) {
const [apiError502, setApiError502] = useState(false);
const [files, setFiles] = useState([]);
useEffect(() => {
// Pull out into a generic reusable function
const getData = async () => {
try {
let apiName = "Dev";
let path = "/test";
let myInit = {
headers: {
Authorization: `Bearer ${(await Auth.currentSession())
.getIdToken()
.getJwtToken()}`
}
};
var result = await API.get(apiName, path, myInit);
setFiles(result); // set your files here
} catch (e) {
if (e.message === "Request failed with status code 502") {
setApiError502(true);
} else {
alert(JSON.stringify(e));
props.onLogout();
}
}
return result;
};
// call getData
getData();
}, []);
return (
<div className="animated fadeIn">
<div>
{Array.isArray(files.Files) && files.Files.map(block => block.Day + ": " + block.file + " ")}
</div>
</div>
);
}
export default dailyFiles;
You're using a functional component so if you want to call the
getData function you should just use getData().
Anyway, since getData() is asynchronous you should make few
changes regarding how you use that inside the render function. For example, you can initially take a variable that has an empty array and once you get the data from the backend inside getData you can reassign that variable with the response data.
Actually you might want to call getData when your component loads for the first time so you can use Hooks for that.
There are several other ways it all comes down to your preference.
I have a app.get which inside of it is quite a bit of logic. Which everything works great aside from some of the logic being called twice for some reason. I have noticed when I was saving something to by db that it would save two rows.
So I put a console.log in that area and sure enough it was logging it twice.
Any reason why this is happening?
app.get('/shopify/callback', (req, res) => {
const { shop, hmac, code, state } = req.query;
const stateCookie = cookie.parse(req.headers.cookie).state;
if (state !== stateCookie) {
return res.status(403).send('Request origin cannot be verified');
}
if (shop && hmac && code) {
// DONE: Validate request is from Shopify
const map = Object.assign({}, req.query);
delete map['signature'];
delete map['hmac'];
const message = querystring.stringify(map);
const providedHmac = Buffer.from(hmac, 'utf-8');
const generatedHash = Buffer.from(
crypto
.createHmac('sha256', config.oauth.client_secret)
.update(message)
.digest('hex'),
'utf-8'
);
let hashEquals = false;
try {
hashEquals = crypto.timingSafeEqual(generatedHash, providedHmac)
} catch (e) {
hashEquals = false;
};
if (!hashEquals) {
return res.status(400).send('HMAC validation failed');
}
// DONE: Exchange temporary code for a permanent access token
const accessTokenRequestUrl = 'https://' + shop + '/admin/oauth/access_token';
const accessTokenPayload = {
client_id: config.oauth.api_key,
client_secret: config.oauth.client_secret,
code,
};
request.post(accessTokenRequestUrl, { json: accessTokenPayload })
.then((accessTokenResponse) => {
const accessToken = accessTokenResponse.access_token;
// DONE: Use access token to make API call to 'shop' endpoint
const shopRequestUrl = 'https://' + shop + '/admin/shop.json';
const shopRequestHeaders = {
'X-Shopify-Access-Token': accessToken,
}
request.get(shopRequestUrl, { headers: shopRequestHeaders })
.then((shopResponse) => {
const response = JSON.parse(shopResponse);
const shopData = response.shop;
console.log('BEING CALLED TWICE...')
res.render('pages/brand_signup',{
shop: shopData.name
})
})
.catch((error) => {
res.status(error.statusCode).send(error.error.error_description);
});
})
.catch((error) => {
res.status(error.statusCode).send(error.error.error_description);
});
} else {
res.status(400).send('Required parameters missing');
}
});