How to inject a service in a api conext? - javascript

I have a api context and I have a service. And I try to write the logic in each of the components.
So I have the service:
const CategoryService = () => {
const fetchCategoryData = async () => {
try {
const response = await fetch("http://192.168.1.68:19000/animal/categories/main_groups/", {
method: "GET",
});
if (!response.ok) {
throw new Error("Network response was not ok");
}
return await response.json();
} catch (error) {
console.error("There was a problem with the fetch operation:", error);
throw error;
}
};
return fetchCategoryData;
};
export default CategoryService;
and I have the context:
import { createContext, useState } from "react";
const CategoryContext = createContext();
const CategoryContextProvier = (props) => {
const [categoryList, setCategoryList] = useState([]);
const [loading, setLoading] = useState(false);
const value = {
categoryList,
loading,
setCategoryList,
setLoading,
};
return <CategoryContext.Provider value={value}>{props.children}</CategoryContext.Provider>;
};
export default CategoryContextProvier;
Question: how to communicate these two witch each other?

you can just call fetchCategoryData in CategoryContextProvier useEffect
like this
const CategoryContextProvier = (props) => {
const [categoryList, setCategoryList] = useState([]);
const [loading, setLoading] = useState(false);
const value = {
categoryList,
loading,
setCategoryList,
setLoading,
};
useEffect(()=>{
setLoading(true);
fetchCategoryData()
.then(res=> setCategoryList(res))
.finally(()=> setLoading(false));
},[])
return <CategoryContext.Provider value={value}>{props.children}</CategoryContext.Provider>;
};

Related

my useFetch custom hook is giving me infinite loop

**the code below is my context which I am using useFetch **
**when i change the url with changing the searchTerm **
** i am getting an infinite loop **
import React, { useContext, useState, useEffect } from "react";
import { useFetch } from "../hooks/useFetch";
const context = React.createContext();
const AppProvider = ({ children }) => {
let url = " https://www.thecocktaildb.com/api/json/v1/1/search.php?s=";
let [searchTerm, setSearchTerm] = useState("a");
useFetch(`${url}${searchTerm}`);
setSearchTerm('s');
return <context.Provider value={"hello"}>
{children}
</context.Provider >
}
const useGlobal = () => {
return useContext(context);
}
export { AppProvider, useGlobal };
** the code below is my custom hook useFetch**
`
import { useEffect, useState } from "react";
export const useFetch = (url) => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
const getData = async () => {
try {
const response = await fetch(url);
const jsonResponse = await response.json();
setData(jsonResponse);
setLoading(false);
} catch (err) {
console.log(err);
}
}
useEffect(() => {
getData();
}, [url])
return { data, loading };
}
`
I tried to change the search Term like this
searchTerm="h"
and it works perfectly but when i change searchTerm with setSearchTerm it gives me infinite loop
setSearchTerm('s'); inside a useEffect
const [url] = useState(" https://www.thecocktaildb.com/api/json/v1/1/search.php?s=");
const [searchTerm, setSearchTerm] = useState("a");
const { data, loading } = useFetch(`${url}${searchTerm}`);
useEffect(() => {
setSearchTerm('s');
}, [])

Why useEffect() didn't report the warning when it performed an unmounted component?

I followed a Reat.js teching video by a YouTube uploarder The Net Ninjia YouTube
In this video, the author indecated a runtime warning:Warning:Can't perform a React state update on an unmounted component.
But according to the following code I can't reproduce this waring.My code works just fine.
So what happened to this following code? Is it because React.js updated something?
import { useState, useEffect } from 'react';
const useFetch = (url) => {
const [data, setData] = useState(null);
const [isPending, setIsPending] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
// const abortCont = new AbortController();
setTimeout(() => {
fetch(url)
.then((res) => {
// console.log(res);
if (!res.ok) {
throw Error('could not fetch data for some reason');
} else {
return res.json();
}
})
.then((res) => {
setData(res);
setIsPending(false);
setError(null);
})
.catch((err) => {
console.log(err);
});
}, 2000);
}, [url]);
return { data, isPending, error };
};
export default useFetch;
However, I followed the video, changed the code as below, it raised a AbortError.But according to the author, this error won't happen.
import { useState, useEffect } from 'react';
const useFetch = (url) => {
const [data, setData] = useState(null);
const [isPending, setIsPending] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const abortCont = new AbortController();
setTimeout(() => {
fetch(url, { signal: abortCont.signal })
.then((res) => {
if (!res.ok) {
throw Error('could not fetch data for some reason');
} else {
return res.json();
}
})
.then((res) => {
setData(res);
setIsPending(false);
setError(null);
})
.catch((err) => {
if (err.name === 'AbortError') {
console.log(err.name);
} else {
setIsPending(false);
setError(err.message);
}
});
}, 2000);
return () => abortCont.abort();
}, [url]);
return { data, isPending, error };
};
export default useFetch;

I want to pull the headers in the data in the useFetch function I created

I want to pull the headers in the data in the useFetch function I created.
What can I write instead of the following function (data + title).
//const {data, loading} = useFetch(data + title);
//DetailPage
import React from 'react';
import { View, Text, ActivityIndicator } from 'react-native';
import useFetch from '../../components/Hooks/useFetch';
import styles from './Detail.style';
const Detail = ({route}) => {
const {title} = route.params;
const {data, loading} = useFetch(data + title);
console.log(title);
if (loading) {
return <ActivityIndicator/>
}
return (
<View style={styles.container}>
<View style={styles.body_container}>
<Text style={styles.title}>{data.title}</Text>
<Text style={styles.description}>{data.description}</Text>
<Text style={styles.programType}>{data.programType}</Text>
<Text style={styles.releaseYear}>{data.releaseYear}</Text>
</View>
</View>
)
}
export default Detail;
//useFetch
import { useState, useEffect } from "react";
const useFetch = () => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchData();
}, []);
const fetchData = async () => {
try {
const response = await fetch('https://gist.githubusercontent.com/hknclk/5710c4adb791755b31ccde6777f04bd2/raw/19954b5d84f476a1d691ce43e4319292893cc27a/sample.json');
const json = await response.json();
setData(json.entries);
setLoading(false);
} catch (error) {
setLoading(false);
}
}
return {data, loading}
}
export default useFetch;
You should be able to access the headers using response.headers
So, once you have a response object, it is just a matter of accessing the iterator and storing it in a format suitable for you. (Feel free to change it)
import { useState, useEffect } from "react";
const useFetch = () => {
const [data, setData] = useState([]);
const [headers, setHeaders] = useState({})
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchData();
}, []);
const fetchData = async () => {
try {
const response = await fetch('https://gist.githubusercontent.com/hknclk/5710c4adb791755b31ccde6777f04bd2/raw/19954b5d84f476a1d691ce43e4319292893cc27a/sample.json');
const json = await response.json();
let headers = {};
for (const kvp of response.headers.entries()) {
headers[kvp[0]] = kvp[1]
console.log(`${kvp[0]}: ${kvp[1]}`);
}
setData(json.entries);
setHeaders(headers)
setLoading(false);
} catch (error) {
setLoading(false);
}
}
return {data, headers, loading}
}
export default useFetch;

How to update lists after delete a category

I want to update the Category list after delete a category, I used custom hook for fetching data from the server. I'm not sure how to update state on custom fetch hook
const {data, error, loading} = useFetch("/api/admin/category");
const [category, setCategory]= useState([]);
useEffect(() => {
setCategory(data)
},[])
const deleteHandler = (id) => {
const deleteRequest = async () => {
const data = await axios.delete(`/api/admin/category/${id}`);
return data;
}
deleteRequest()
.then(res => {
data.filter((item) => {
return id !== item.id;
})
})
}
Adding data as the dependency to the useEffect hook may help, try this,
const {data, error, loading} = useFetch("/api/admin/category");
const [category, setCategory]= useState([]);
useEffect(() => {
setCategory(data)
},[data])
const deleteHandler = (id) => {
const deleteRequest = async () => {
const data = await axios.delete(`/api/admin/category/${id}`);
return data;
}
deleteRequest()
.then(res => {
data.filter((item) => {
return id !== item.id;
})
})
}
could you add you're custom hook to the code provided? and also be a bit more specific with your query?
import {useEffect, useState} from "react";
import axios from "axios";
const useFetch = (url) => {
const [data, setData,isLoading] = useState([]);
const [error, setError] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
request_get()
.then(res => {
if (res.request.status === 200) {
setTimeout(() => {
setLoading(false)
setData(res.data.data)
},1000)
}
})
return () => {
setData([]);
}
}, [])
const request_get = async () => {
const data = await axios.get(url)
return data;
}
return {data: data, error: error, loading:loading}
}
export default useFetch;
in your custom hook add data to your dependency array;
in your component instead of the folowing
useEffect(() => {
setCategory(data)
},[])
try to use the spread operator
useEffect(() => {
setCategory([...data])
},[data])

Using the Context API gives me undefined

So I'm using Auth0 for my user sign up. I'm trying to get the user id under sub:value to add to my database to identify with the post of a user. I'm trying to use a Context API in order to get the user info to put in my database.
react-auth0-spa.js
// src/react-auth0-spa.js
import React, { useState, useEffect, useContext } from "react";
import createAuth0Client from "#auth0/auth0-spa-js";
const DEFAULT_REDIRECT_CALLBACK = () =>
window.history.replaceState({}, document.title, window.location.pathname);
export const Auth0Context = React.createContext();
export const useAuth0 = () => useContext(Auth0Context);
export const Auth0Provider = ({
children,
onRedirectCallback = DEFAULT_REDIRECT_CALLBACK,
...initOptions
}) => {
const [isAuthenticated, setIsAuthenticated] = useState();
const [user, setUser] = useState();
const [auth0Client, setAuth0] = useState();
const [loading, setLoading] = useState(true);
const [popupOpen, setPopupOpen] = useState(false);
useEffect(() => {
const initAuth0 = async () => {
const auth0FromHook = await createAuth0Client(initOptions);
setAuth0(auth0FromHook);
if (window.location.search.includes("code=") &&
window.location.search.includes("state=")) {
const { appState } = await auth0FromHook.handleRedirectCallback();
onRedirectCallback(appState);
}
const isAuthenticated = await auth0FromHook.isAuthenticated();
setIsAuthenticated(isAuthenticated);
if (isAuthenticated) {
const user = await auth0FromHook.getUser();
setUser(user);
}
setLoading(false);
};
initAuth0();
// eslint-disable-next-line
}, []);
const loginWithPopup = async (params = {}) => {
setPopupOpen(true);
try {
await auth0Client.loginWithPopup(params);
} catch (error) {
console.error(error);
} finally {
setPopupOpen(false);
}
const user = await auth0Client.getUser();
setUser(user);
setIsAuthenticated(true);
};
const handleRedirectCallback = async () => {
setLoading(true);
await auth0Client.handleRedirectCallback();
const user = await auth0Client.getUser();
setLoading(false);
setIsAuthenticated(true);
setUser(user);
};
return (
<Auth0Context.Provider
value={{
isAuthenticated,
user,
loading,
popupOpen,
loginWithPopup,
handleRedirectCallback,
getIdTokenClaims: (...p) => auth0Client.getIdTokenClaims(...p),
loginWithRedirect: (...p) => auth0Client.loginWithRedirect(...p),
getTokenSilently: (...p) => auth0Client.getTokenSilently(...p),
getTokenWithPopup: (...p) => auth0Client.getTokenWithPopup(...p),
logout: (...p) => auth0Client.logout(...p)
}}
>
{children}
</Auth0Context.Provider>
);
};
other.js (trying to get user info from react-auth0-spa.js)
class AddAlbum extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
let value = this.context;
console.log(value);
}
render() {
return (
)
}
AddAlbum.contextType = Auth0Context;
This gives me user: undefined
In my index.js I have this
ReactDOM.render(
<Auth0Provider
domain={config.domain}
client_id={config.clientId}
redirect_uri={window.location.origin}
onRedirectCallback={onRedirectCallback}
>
<App />
</Auth0Provider>,
document.getElementById("root")
);
Which I believe is giving me these results:
So I'm wondering why my Context API isn't working and giving me user: undefined.
You're logging the user when the component first mounts, which is long before the await auth0FromHook.getUser() call will complete. Log it in a componentDidUpdate, or check in a parent if that value is available, and don't mount the child component until it is.

Categories

Resources