Fetching data through Query Component inside react's useEffect - reactjs

I am using react-apollo's <Query> component inside my function component to fetch data from Apollo server graphql microservice. I want to update the state of my component using useEffect hook and Query component.
I tried using Query component within useEffect function, but the request is not going without giving any error
const foo = () => {
const [bar, setBar] = useState([]);
const fetchBars = () => (<Query query={fetchQuery}>{({loading, error, data}) => {
if(!loading) console.log(data);
}})
useEffect(() => {
fetchBars();
}, []);
}
Ideally, it should call graphql api and fetch the data but console is not coming up. I tried using axios library instead of Query component and the request is going through, but I don't want to introduce new stuff to do same thing.

Related

storing the response using useEffect to avoid re-rendering using react hooks

I am using React hooks and trying to figure out, how should I store the response of the api call response.data._embedded.assets in a state variable.
Using setAssets(response.data._embedded.assets); doesn't work because of re-rendering. So I decided to use useEffect as shown in the code below but this violates the rules of react
hooks -Hooks can only be called inside of the body of a function component. I understand that useEffect should be defined outside as per react hooks but then how would I store the response in a state variable ? Please advise.
const [selectedTabIndex, setselectedTabIndex] = useState(0);
const [assets,setAssets] = useState([]);
let companyCategory;
axios
.get(url, {
params: {
assetCategoryId: selectedTabIndex
}
}).then(response => {
if (sessionStorage.getItem('companyCategory') !== null) {
companyCategory = JSON.parse(sessionStorage.getItem('companyCategory') )
}
console.log("Inside response of web api call");
console.log(response.data._embedded.assets);
useEffect(() => {
// Should not ever set state during rendering, so do this in useEffect instead.
setAssets(response.data._embedded.assets);
}, []);
//setAssets(response.data._embedded.assets);
}).catch(err => console.log(err));
In a class component, the above state variable declaration would be like this inside the response:
this.setState({
companyCategory: companyCategory,
assets: response.data._embedded.assets
})
I would put the whole get request in useEffect.
const [selectedTabIndex, setselectedTabIndex] = useState(0);
const [assets,setAssets] = useState([]);
useEffect(() => {
// Should not ever set state during rendering, so do this in useEffect instead.
let companyCategory;
axios
.get(url, {
params: {
assetCategoryId: selectedTabIndex
}
}).then(response => {
if (sessionStorage.getItem('companyCategory') !== null) {
companyCategory = JSON.parse(sessionStorage.getItem('companyCategory') )
}
console.log("Inside response of web api call");
console.log(response.data._embedded.assets);
setAssets(response.data._embedded.assets);
}).catch(err => console.log(err));
}, []);
If a component doesn't need to render when it changes, don't put it in state. You can have a module-scope variable in your component and use that.
With class components, you can also put it on this
why do you fetch data if you don't want to use that,
also we can't use react hooks inside functions
Call Hooks from React function components
Call Hooks from custom Hooks

Infinite loop on componentdidupdate with useEffect

I'm using redux and trying to fetch data when my component did update.
I'm using useEffect hook to track posts update and getting the state with useSelector.
I'm having issues as the component is making infinite fetching requests instead of a single request.
Anyone knows how I can stop it from making infinite requests
and make a single request if posts updated?
my code:
const posts = useSelector((state) => state.posts.posts);
useEffect(() => {
dispatch(getPosts(page));
}, [posts]);
image showing infinite fetching requests being made
From useEffect documentation
If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.
So, dispatch(getPosts(page)) will be called on component mount as well when any of the dependency provided get changed, this will make an API request and fetch the posts of this page. Which will eventually update the state.posts.posts once the API is successful. As, the same state.posts.posts is given as dependency to the useEffect hook this will trigger the function to get executed again and the cycle goes on.
For example if you want to make the API call and fetch new posts when there's a change in the page you should provide page as dependency instead of posts as shown below
const posts = useSelector((state) => state.posts.posts);
useEffect(() => {
dispatch(getPosts(page));
}, [page]);
const posts = useSelector((state) => state.posts.posts);
useEffect(() => {
dispatch(getPosts(page));
}, []);
const updateNeeded = useSelector((state) => state.posts.updateNeeded);
useEffect(() => {
if (updateNeeded) {
dispatch(getPosts(page));
}
}, [updateNeeded]);
Change updateNeeded to true by a dispatch action when you want to fetch a new update, and when the update is fetched dispatch an action which will make this flag to false again.

How to fix multiple call fetch data in forEach() using React Hooks

In react Hooks, I am trying to fetch data from the API array but in the Foreach function, the API call causes infinity.
How to fix this?
const [symbols, setSymbols] = useState([]);
getPortfolioSymbolList(portfolio_name).then(data => data.json()).then(res => {
res.forEach((symbol_data)=>{
fetchPrice(symbol_data.symbol).then(price => {
setSymbols(price);
});
})
}
function fetchPrice(symbol){
const price = fetch(`api_url`)
.then(chart => chart.json())
return price;
}
Here, call fetchPrice() causes in infinite.
Setting the state will always cause a rerender
What happens in your code is the request is made and then the data is set causing a rerender. Then because of the rerender the request is made again and sets the state again and causes the rerender again.
If you have a request for data you probably want to put a React.useEffect so it only requests once.
React.useEffect(() => {
/* your data request and data set */
}, []); // the [] will only fire on mount.
Is is because your setSymbols call inside forEach makes component rerender (reload) - it means that all of your main component function is call again and again... getPortfolioSymbolList too. You have to use useEffect hook to resolve this problem. Your getPortfolioSymbolList() API call should be inside useEffect.
https://reactjs.org/docs/hooks-effect.html
PROBLEM
Your first symbol is updated in your API call, which triggers a re-render of the component calling the API call to go on an infinite loop.
SOLUTION
Wrap your API in your useEffect. The function inside your useEffect will only be called once. See useEffect docs here
You need to use for await of to loop asynchronously. forEach can't loop asynchronously. See for await of docs here
Update your symbols once all the data is collected.
function Symbols() {
const [symbols, setSymbols] = useState([]);
React.useEffect(() => {
async function fetchSymbols() {
const portfolio = await getPortfolioSymbolList(portfolio_name);
const jsonPortfolios = await data.json();
const symbols = [];
for await (let jsonPortfolio of jsonPortfolios) {
const price = await fetchPrice(jsonPortfolio.symbol);
symbols.push(price);
}
setSymbols(symbols);
}
fetchSymbols();
}, []);
return /** JSX **/
}

React: Stop hook from being called every re-rendering?

Somewhat new to React and hooks in React. I have a component that calls a communications hook inside of which a call to an API is made with AXIOS and then the JSON response is fed back to the component. The issue I'm having is the component is calling the hook like six times in a row, four of which of course come back with undefined data and then another two times which returns the expected JSON (the same both of those two times).
I did a quick console.log to double check if it was indeed the component calling the hook mulitple times or it was happening inside the hook, and it is the component.
How do I go about only have the hook called only once on demand and not multiple times like it is? Here's the part in question (not including the rest of the code in the widget because it doesn't pertain):
export default function TestWidget() {
//Fetch data from communicator
console.log("called");
const getJSONData = useCommunicatorAPI('https://jsonplaceholder.typicode.com/todos/1');
//Breakdown passed data
const {lastName, alertList, warningList} = getJSONData;
return (
<h1 id="welcomeTitle">Welcome {lastName}!</h1>
);
}
export const useCommunicatorAPI = (requestAPI, requestData) => {
const [{ data, loading, error }, refetch] = useAxios('https://jsonplaceholder.typicode.com/todos/1', []);
console.log("data in Communicator:", data);
return {data};
}
I would use the useEffect hook to do this on mount and whenever any dependencies of the request change (like if the url changed).
Here is what you will want to look at for useEffect
Here is what it might look like:
const [jsonData, setJsonData] = React.useState({})
const url = ...whatver the url is
React.useEffect(() => {
const doFetch = async () => {
const jsonData = await useAxios(url, []);;
setJsonData(jsonData)
}
doFetch();
}, [url])
...use jsonData from the useState
With the above example, the fetch will happen on mount and if the url changes.
Why not just use the hook directly?
export default function TestWidget() {
const [{ data, loading, error }, refetch] =
useAxios('https://jsonplaceholder.typicode.com/todos/1', []);
return (<h1 id="welcomeTitle">Welcome {lastName}!</h1>);
}
the empty array [] makes the hook fire once when called
Try creating a function with async/await where you fetch the data.
Here can you learn about it:
https://javascript.info/async-await

Using useEffect with Axios API call without constant rerendering (with Typescript)

I'm fetching data from an API within a file which is the context provider of my React application. However, when I push some data to the API, from a component consuming the context, the data isn't updated in real time, and I have to refresh the page to see it update. How do I make sure it keeps checking the API for new data?
I have added the items state to the dependency array in the useEffect function but this results in the API being constantly called, as opposed to only when the data changes.
ItemsContext.tsx
const [items, setItems] = useState();
useEffect(() => {
const fetchData = async () =>
{
try {
const res = await axios.get(config().URI);
setItems(res.data.items);
} catch (error) {
throw error;
}
};
fetchData();
}, []);

Resources