How to fix missing dependency in React applications using useEffect? - javascript

Getting this error in my console. Not sure how to handle them
I am passing in guildId, so im not sure why its logging this error
src/utils/hooks/useFetchGuildBans.tsx
Line 22:6: React Hook useEffect has a missing dependency:
'guildId'. Either include it or remove the dependency array
react-hooks/exhaustive-deps
Here is my useFetchGuildBans.tsx
import { useEffect, useState } from 'react';
import { getGuildBans } from '../api';
import { GuildBanType } from '../types';
export function useFetchGuildBans(guildId: string) {
const [bans, setBans] = useState<GuildBanType[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState();
const [updating, setUpdating] = useState(false);
useEffect(() => {
setLoading(true);
getGuildBans(guildId)
.then(({ data }) => {
setBans(data);
})
.catch((err) => {
console.log(err);
setError(err);
})
.finally(() => setLoading(false));
}, [updating]);
return { bans, loading, error, updating, setUpdating };
}

useEffect(() => {
setLoading(true);
getGuildBans(guildId)
.then(({ data }) => {
setBans(data);
})
.catch((err) => {
console.log(err);
setError(err);
})
.finally(() => setLoading(false));
}, [updating, guildId]);
The second parameter of useEffect is called the dependencies array. The error message is saying that guildId is missing from this array.

Related

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;

React simple useEffect infinit loop

I do not understand why this code is an infinit loop. I this it is because I update my state in else if condition. But i'd like to update an array of urls when getting new api answer.
import React, { useState, useEffect } from 'react';
function getShortenUrl() {
const [urls, setUrls] = useState([])
const [error, setError] = useState(null);
const [items, setItems] = useState({});
useEffect(() => {
fetch("https://api.shrtco.de/v2/shorten?url=https://stackoverflow.com/questions/37435334/correct-way-to-push-into-state-array")
.then(res => res.json())
.then(
(result) => {
setItems(result);
},
(error) => {
setError(error);
}
)
}, [])
if (error) {
return <div>Error : {error.message}</div>;
} else if (!items.result) {
return <div>Loading...</div>;
console.log("no item");
} else {
setUrls([urls, items]);
console.log("items", items);
console.log("urls", urls);
return <ul> {items.result.short_link}</ul>;
}
}
export default getShortenUrl;
I am kindof lost when it comes to state actually. I do not understand how I can create an array of urls and be able to use it in other components.
You may have some mistakes here
.then(
(result) => {
setItems(result);
},
(error) => {
setError(error);
}
)
Change it into
.then((result) => {
setItems(result);
setUrls([...urls, result])
})
.catch((error) => {
setError(error);
})
And also remove the line setUrls([urls, items]);
If you are new to react then we make Loading state for API Call fetch and you are setting state in else and when state updates component re-renders so on every component re-render you are updating state which is causing infinite loop. Try this
import React, { useState, useEffect } from 'react';
function getShortenUrl() {
const [urls, setUrls] = useState([])
const [error, setError] = useState(null);
// const [items, setItems] = useState({}); // remove it because you are using urls and items state for same purposes
const [loading,setLoading]=useState(false);
useEffect(() => {
setLoading(true);
fetch("https://api.shrtco.de/v2/shorten?url=https://stackoverflow.com/questions/37435334/correct-way-to-push-into-state-array")
.then(res => res.json())
.then(
(result) => {
// setItems(result); // remove it
setUrls(result);
setLoading(false);
},
(error) => {
setError(error);
setLoading(false);
}
)
}, [])
if(loading){
return <div>Loading...</div>;
}
if (error) {
return <div>Error : {error.message}</div>;
} else {
return <ul> {urls?.result?.short_link}</ul>;
}
}
export default getShortenUrl;
Try to use a conditional rendering instead of if else statement:
import React, { useState, useEffect } from 'react';
function getShortenUrl() {
const [urls, setUrls] = useState([])
const [error, setError] = useState(null);
const [items, setItems] = useState({});
useEffect(() => {
fetch("https://api.shrtco.de/v2/shorten?url=https://stackoverflow.com/questions/37435334/correct-way-to-push-into-state-array")
.then(res => res.json())
.then(
(result) => {
setItems(result);
},
(error) => {
setError(error);
}
)
}, [])
return (
<>
{error&& <div>Error : {error.message}</div>}
{!items.result && <div>Loading...</div> }
{items.result && <ul> {items.result.short_link}</ul>}
</>
)
}
export default getShortenUrl;

Does order of state variable matters in React?

When I execute the code below gives an error "Cannot read properties of null (reading 'login')", because it reaches the return statement at the end, which it should not as I already have checks for the boolean before return.
import React, { useState, useEffect } from 'react';
const url = 'https://api.github.com/users/QuincyLarsn';
const MultipleReturns = () => {
const [isLoading, setIsLoading] = useState(true);
const [isError, setIsError] = useState(false);
const [user, setUser] = useState(null);
useEffect(() => {
fetch(url)
.then(data => {
if (data.status >= 200 && data.status <= 299)
return data.json();
else {
console.log("here");
setIsLoading(false);
setIsError(true);
console.log("here 2");
}
})
.then(result => {
setIsLoading(false);
setUser(result);
})
.catch(error => console.log(error))
}, []);
console.log(isError);
if (isLoading)
return <h2>Loading...</h2>
if (isError) {
return <h2>Error...</h2>
}
return <h2>{user.login}</h2>
};
export default MultipleReturns;
In the above code if setIsError(true) is placed before setIsLoading(false) in useEffect, then everything works fine but not vice versa, similarly if the url is correct then too things work fine if setUser(result) is placed before setIsLoading(false) and not vice versa.
I am not able to figure out why that is the case.
React is not batching state updates from fetch(). It is batched in case of event listeners. This is an async fetch call.
In this sandbox console, you can see that there is a render in between your state updates - setIsLoading(false) and setIsError(true).
So for one render cycle : isLoading is false and isError is also false. That will lead to the error condition.
You can use unstable_batchedUpdates to enforce batching.
import { useEffect, useState } from "react";
import { unstable_batchedUpdates } from "react-dom";
import "./styles.css";
const url = "https://api.github.com/users/QuincyLarsn";
const App = () => {
const [isLoading, setIsLoading] = useState(true);
const [isError, setIsError] = useState(false);
const [user, setUser] = useState(null);
useEffect(() => {
fetch(url)
.then((data) => {
if (data.status >= 200 && data.status <= 299) return data.json();
else {
console.log("here");
unstable_batchedUpdates(() => {
setIsLoading(false);
setIsError(true);
});
console.log("here 2");
}
})
.then((result) => {
setIsLoading(false);
setUser(result);
})
.catch((error) => {
console.log(error);
});
}, []);
console.log("isError", isError);
if (isLoading) return <h2>Loading...</h2>;
if (isError) return <h2>Error...</h2>;
return <h2>{user.login}</h2>;
};
export default App;
Corrected Sandbox Link
In a such case, order does matter.
While React may batch updates in this case, it's not guaranteed and even if it does, it may call the render function with the in-between state.
So, when isLoading is set to false, but user is not yet set, you get an error.
You can fix this by setting the user first, and then making isLoading false.
But the real solution would be to eliminate the unnecessary state variables: isLoading is true while isError is false and user is null, and false otherwise.
So, you can do it like this:
should not as I already have checks for the boolean before return.
import React, { useState, useEffect } from 'react';
const url = 'https://api.github.com/users/QuincyLarsn';
const MultipleReturns = () => {
const [isError, setIsError] = useState(false);
const [user, setUser] = useState(null);
useEffect(() => {
fetch(url)
.then(data => {
if (data.status >= 200 && data.status <= 299)
return data.json();
else {
console.log("here");
setIsError(true);
console.log("here 2");
}
})
.then(result => {
setUser(result);
})
.catch(error => console.log(error))
}, []);
console.log(isError);
if (isError) {
return <h2>Error...</h2>
}
if (user !== null) {
return <h2>{user.login}</h2>
}
return <h2>Loading...</h2>
};
export default MultipleReturns;
After you set isLoading as false, the code moves to the last return statement as the error is still false at the moment. So first setting the error blocks the code at the second return statement.
Similarly if you set isLoading as false then set the user, the code will move to the last return statement before the user is set and it will show error. Setting the user and then making isLoading as false shows the user perfectly.

How to connect flask rest API output to react and display result

I am doing inference using flask rest API and I got the result
{
result: {
predictions: -3.4333341121673584
} }
bypassing multiple args in the get as the URL I got the above result
http://127.0.0.1:3000/predict?solute=CC(C)(C)Br&solvent=CC(C)(C)O Now I want to use this result to use in a react app.
I have written the code below
import { useState, useEffect } from "react";
function App() {
const [state, setState] = useState({});
useEffect(() => {
fetch("api/")
.then((response) => {
if (response.status == 200) {
return response.json();
}
})
.then((data) => console.log(data))
.then((error) => console.log(error));
});
I have written the following using a tutorial on the internet. I am new to using fetch API or Axios. Need help to get this result in react app
import { useState, useEffect } from "react";
function App() {
const [data, setData] = useState(null);
const [loading, setLoading = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch("http://127.0.0.1:3000/predict?solute=CC(C)(C)Br&solvent=CC(C)(C)O")
.then((response) => {
if (response.status == 200) {
return response.json();
}
})
.then(setData)
.catch(setError)
.finally(() => setLoading(false));
}, []);
if (loading) {
return <p>Loading</p>
}
if (error) {
return <p>{JSON.stringify(error)}</p>
}
return <p>{JSON.stringify(data)}</p>
}

How to render a list from a JSON url? - ReactJS hooks

I want to render a list from a JSON URL. However, I have the following error: Objects are not valid as a React child (found: TypeError: Failed to fetch). If you meant to render a collection of children, use an array instead. What am I going wrong? Thanks for your answer
//hooks.tsx
import { useEffect, useState } from 'react'
export const useFetch = () => {
const [data, setData] = useState([])
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
useEffect(() => {
setLoading(true)
setError(null)
fetch('https://jsonkeeper.com/b/Z51B')
.then(res => res.json())
.then(json => {
setLoading(false)
if (json.data) {
setData(json.data)
} else {
setData([])
}
})
.catch(err => {
setError(err)
setLoading(false)
})
}, [])
return { data, loading, error }
}
//index.tsx
import React from 'react';
import { useFetch } from "./hooks.js";
import {CardItem} from './card';
export const List = () => {
const { data, loading, error } = useFetch()
if (loading) return <div>Loading...</div>
if (error) return <div>{error}</div>
return (
<>
<ul>
{data.map((item: any, index: any) => (
<li key={index}>
{item.names.map((name: any) => {
return <CardItem
family={item.family}
name={name}
/>
})
}
</li>
))}
</ul>
</>
);
};
I guess the problem is with your setError(err) in catch block of your custom hook. It should be setError(err.message).

Categories

Resources