New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
React Hook useEffect has a missing dependency: 'xxx' ? #15865
Comments
This should answer your question: https://reactjs.org/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies |
@gaearon |
My question is :React Hook cannot call a function in the useEffect and function component to setState operation? |
Leaving open so we can respond to second question. |
I'm having the same ESLint warning but in my case I want to make an async call when my component is mounted. const ManageTagsModalBody: React.FC<IProps> = ({ children, getTags }) => {
useEffect(() => {
getTags();
}, []);
return <div>{children}</div>;
};
I'm not sure what to add to the list of dependencies. |
i'm interested for an explanation also.
|
Same issue here. Strange rule. |
Same here. As simple as in #15865 (comment):
Is there a way to suppress this warning? |
As suggested in the warning message, you can do like that
|
@fayway then whenver initFetch and dispatch value changed, useEffect's callback will be execute. |
@shkyung In my case, initFetch will not change cause (store.)dispatch doesn't either |
Maybe it can be like this const setCenterPosition = useRef(null)
setCenterPosition.current = useCallback( ()=>{} ,[deps])
effect(()=>{ setCenterPosition.current() },[setCenterPosition,otherDeps]) |
This change seems a bit ridiculous and counter productive to be quite frank. Rather rollback to an earlier version and let you think this one through. |
Have the same issue. I only want my fetch to fire on componentDidMount. Adding the dependency to the array results in repeatedly hitting the endpoint. |
React Hook useEffect has a missing dependency: 'dispatch'.
|
This seems to be quite a common use case - one that I have run into on my current project. You want to run an effect hook just one time, but there IS a dependancy, although you only care about the state of that at startup. Currently using |
Closing Lint is just a temporary solution, the key to this problem is not enough to understand the hook. |
Same issue here. I just wanted to fire a function inside useEffect() once, having [] as second parameter does what I want, but it keeps giving this warning. |
Such a weird warning because I've never seen it before until today on a new project. It ruins the use case of having something called only once when component has mounted. There doesn't seem to be any workaround except ignoring the lint warning. |
Id like to put in my two cents here. In particular with using Axios to cancel a network request. Will create a separate issue if required but felt this issue directly affected myself. So my useApi hook is as follows - import axios, { AxiosInstance } from "axios";
import axiosRetry from "axios-retry";
import { FetchEnv } from "../../utilities";
import { useStorage } from "../useStorage";
export const useApi = ({ isAuth = false, retries = 3 } = {}) => {
const cancelToken = axios.CancelToken.source();
const { getItem } = useStorage();
const getBaseUrl = () => {
return FetchEnv({
defaultValue: "http://api.example.com",
key: "API_URI"
});
};
const authorizedClient = (client: AxiosInstance) => {
const session = getItem("SESSION", "sessionStorage");
const hasAccessToken = Boolean(session.tokens.accessToken);
if (isAuth && !hasAccessToken) {
console.error("No access token found to initiate authorized request.");
return client;
} else {
client.defaults.headers[
"Authorization"
] = `Bearer ${session.tokens.accessToken}`;
return client;
}
};
const buildFetch = (): AxiosInstance => {
const client = axios.create({
baseURL: getBaseUrl(),
cancelToken: cancelToken.token
});
axiosRetry(client, { retries });
return isAuth ? authorizedClient(client) : client;
};
return {
cancelRequest: cancelToken.cancel,
fetch: buildFetch()
};
}; To use this hook within a component, simply define it as below then it can be used to make both authenticated and unauthenticated calls either on mount, within a useEffect, as part of an event handler, etc. The cancelRequest is the unique cancel token generated that is paired with the "fetch" axios instance relative to this component. const { cancelRequest, fetch } = useApi(); If for any reason this component dismounts, the following is called: useEffect(() => {
return () => {
cancelRequest("Auth network request cancelled");
};
}, []); Now it works perfectly at present. However, the warning, when applied (putting cancelRequest as a useEffect dependency) immediately CANCELS the network request when the fetch method is called. Any advice would be greatly appreciated however it would appear the only solution at present would be to ts-lint disable this moving forward... |
I think the issue here may be the way we are thinking about hooks. @luojinghui's comment suggests that there is more to this than meets the eye. Perhaps we need to think differently? I have been able to remove this problem in one of my hooks with some refactoring. The code is clearer as a result. It led me to wonder if, in @Stoner609's example just above this, the timing code should be in a useCallback hook? It is still odd having a function (which should be static) as a dependancy though. |
I think this case should be some sort of exception |
If you want to run a function only once when the component loads and which takes in parameters then you can use useRef to avoid the warning. Something like this works:
|
As much as I love this witty reply this usually is what happens in my code. I'd love to know exactly what and why happens in that array of mystery :) |
this also may create a memory leak in case of something like an API, it will make the call on an infinite loop. |
@kennylbj well I do unregister but still it not a good practise |
Seems like your listener is called twice even if the socket id are the same. I don't think this will happen if the following situation meets: // call useEffect if and only if sockeId changed.
useEffect(() => {
const unregister = register(socketId);
return () => unregister(socketId);
}, [socketId]) Are there any other variables in the dependencies array changed during different renders and cause this behavior? |
Yeah 3 dependencies, but I figure it out some different way |
ぴえん |
wow,非常感谢你🙏 |
🚀 Below code snippet works really well for me On Component did mount
On parameter change
|
Best work-around: react-hooks/exhaustive-deps: "off" |
nice work. |
I don't think the react docs quite cover @luojinghui 's use case, that is also the same that I have: We have multiple ways of calling a given function, ie: The react docs suggest
But usually in real-world examples, we need to reuse functions like we normally would with instance methods on a class component ( I'm not actually sure, but maybe the solution is
...but that's kinda gross to me, and I'm hoping there's a cleaner way. Maybe @gaearon can confirm? |
facing the same issue i can disable the warning bu using this line at the end of useEffect Here's My code `const [items, setItems] = useState([ useEffect(() => { |
My solution to this problem has been to simply stop using React Hooks for these cases. If you component needs lots of state logic and lifecycle events like I'll be limiting my own use of React Hooks to simple ones like (Edited for clarity). |
This is my solution for now: const mounted = () => {
dispatch(something());
}
useEffect(mounted, []); |
What's the point on adding the function into the dependency Array? What's the point on those warnings? Kinda stupid |
Please read an article on the topic. https://reacttraining.com/blog/when-to-use-functions-in-hooks-dependency-array/ |
this works for me const dispatch = useDispatch()
useEffect(() => {
async function fetch() {
try {
const { data } = await getDiscussionByTitle(params.title)
setDiscussion(data)
} catch (error) {
dispatch(addRequestError({ message: error.response.data }))
}
}
fetch()
}, [params.title, dispatch]) |
This is what solved my problem. Don't forget to |
This is a reasonably common issue, which can be solved by passing your dependency into the dependency array. In the OP's example it could be solved by passing If this warning is not handled it can cause memory leaks in your application as it can cause infinite loops and re-render issues. In the case that you want an effect to only be ran once, Chris Coyier has an excellent example here For more information though, as @gaearon said, it can be found here: |
Did anyone find a way to call a function inside a useEffect with empty array callback without warning and without adding bullshit code ? React has the power to make easy things impossible. I love it. |
I agree with you @luojinghui Please reopen this issue. I want to know the complete solution for this ... |
I want to execute useEffect only when specific attributes are changed, not the dependent parameters in useEffect. But eslint will warn me, how to solve it |
Hi, a possible solution is to simulate the class constructor @see Adam Nathaniel Davis post: |
Well then put those attributes into the dependency array, and as for avoiding the eslint warning: also put the eslint line (below added) at the end of the useEffect to not let it call warning and work as expected hopefully. |
This still feels like an issue or at least a bit confusing... Or am i just dumb and misusing my useEffect? Example: const [id, setId] = useState(null)
const [stateData, setStateData] = useState()
useEffect(() => {
const fetchData = async () => {
const data = fetch(`/data/${id}`);
if (data) {
setStateData(data);
}
};
if (id) { // only fetch data if id is set
fetchData();
}
}, [id]); // React Hook useEffect has a missing dependency: 'setData'. Either include it or remove the dependency array. Example with out warrning const [id, setId] = useState(null)
const [stateData, setStateData] = useState()
useEffect(() => {
const fetchData = async () => {
const data = fetch(`/data/${id}`);
if (data) {
setStateData(data);
}
};
if (id) { // only fetch data if id is set
fetchData();
}
}, [id, setStateData]); // No warning but results in a infinity loop |
I'm presuming that your variable names are mixed up, and that
Source: https://reactjs.org/docs/hooks-reference.html#usestate However, it should not be rerunning the If by chance your |
you are right, it should be
And yes it's an function exported and passed down by a context.. export const StateContext = React.createContext({});
export const StateContextProvider: React.FC = ({ children }) => {
const [stateData, setStateData] = useState()
const setStateData = (key: string, value: any) => {
setState((prev) => {
return {
...prev,
[key]: value,
};
});
};
....
return (
<StateContext.Provider
value={{
...state,
setStateData
}}
>
{children}
</StateContext.Provider>
);
};
export const useStateContext = () => React.useContext(StateContext); Then used like this. const [id, setId] = useState(null)
const {stateData, setStateData} = useStateContext()
useEffect(() => {
const fetchData = async () => {
const data = fetch(`/data/${id}`);
if (data) {
setStateData(data);
}
};
if (id) { // only fetch data if id is set
fetchData();
}
}, [id, setStateData]); // No warning but results in a infinity loop So it seems to be me being dumb and using it wrong. |
Not dumb. I also find hook dependencies to be rather confusing, and often screw up my code without realizing it. In your case, you can probably use
->
|
To fix hook dependency warnings, add the below code in the package.json file below the eslintConfig. |
Hi, I am researching React Hook recently, it's great.
But I have a problem, I did not find a suitable answer in the React Hook documentation and google to solve my problem.
When I used a function in useEffect and function component together, I encountered a warning that I did not specify a dependency in useEffect, as shown below:
Is there any way to solve my problem? I have thought about it for a long time.
What is the current behavior?
Mini repro in codesandbox:
https://codesandbox.io/s/trusting-kowalevski-oet4b
Any solution, thanks.
Code
The text was updated successfully, but these errors were encountered: