Reputation: 15
I am trying to Save to Local in React and my app is working, but I cannot deploy it because of this warning. The warning is:
React Hook useEffect has a missing dependency: 'saveLocalTodos'. Either include it or remove the dependency array
And my code is:
// Run once when the app starts
useEffect(() => {
getLocalTodos();
}, []);
// useEffect
useEffect(() => {
// Function
function filterHandler() {
switch (status) {
case `completed`:
setFilteredTodos(todos.filter((todo) => todo.completed === true));
break;
case `uncompleted`:
setFilteredTodos(todos.filter((todo) => todo.completed === false));
break;
default:
setFilteredTodos(todos);
break;
}
}
filterHandler();
saveLocalTodos();
}, [todos, status]);
// Save to Local
const saveLocalTodos = () => {
localStorage.setItem("todos", JSON.stringify(todos));
};
const getLocalTodos = () => {
if (localStorage.getItem("todos") === null) {
localStorage.setItem("todos", JSON.stringify([]));
} else {
let todoLocal = JSON.parse(localStorage.getItem(`todos`));
setTodos(todoLocal);
}
};
Upvotes: 1
Views: 1473
Reputation: 434
You are getting this error because inside useEffect
you're calling getLocalTodos
, saveLocalTodos
function which are defined outside of useEffect. Ideally inside useEffect dependency array you should define all the outer function, props variable etc. which are used inside useEffect
. So whenever there is any changes in the dependency the effect will be triggered inside useEffect
. When you are creating any function wrap that function inside React.useCallback
and there you can pass dependency of that particular function , just like for your case saveLocalTodos
is dependent on todos, so your function will only change when todos will change. In that way your function will change only when necessary.
const filterHandler = React.useCallback(() => {
switch (status) {
case `completed`:
setFilteredTodos(todos.filter((todo) => todo.completed === true));
break;
case `uncompleted`:
setFilteredTodos(todos.filter((todo) => todo.completed === false));
break;
default:
setFilteredTodos(todos);
break;
}
}, [todos, status]);
// Save to Local
const saveLocalTodos = React.useCallback(() => {
localStorage.setItem("todos", JSON.stringify(todos));
}, [todos]);
const getLocalTodos = React.useCallback(() => {
if (localStorage.getItem("todos") === null) {
localStorage.setItem("todos", JSON.stringify([]));
} else {
let todoLocal = JSON.parse(localStorage.getItem(`todos`));
setTodos(todoLocal);
}
},[]);
useEffect(() => {
filterHandler();
saveLocalTodos();
getLocalTodos();
}, [getLocalTodos, filterHandler, saveLocalTodos]);
Upvotes: 1
Reputation: 4938
Just include your dependency in the dependencies array of React.useEffect
then.
You're using saveLocalTodos
inside your useEffect
but not defining it in the dependencies array. Normally, the rule of thumb is to include everything (functions, variables, state, props) which is used inside the useEffect
to be in the dependencies array. Because your effect depends on them and should reinvoke itself once their value changes.
const saveLocalTodos = React.useCallback(() => {
localStorage.setItem("todos", JSON.stringify(todos));
}, [todos]);
useEffect(() => {
// Function
function filterHandler() {
switch (status) {
case `completed`:
setFilteredTodos(todos.filter((todo) => todo.completed === true));
break;
case `uncompleted`:
setFilteredTodos(todos.filter((todo) => todo.completed === false));
break;
default:
setFilteredTodos(todos);
break;
}
}
filterHandler();
saveLocalTodos();
}, [todos, status, saveLocalTodos]);
Also, wrap your saveLocalTodods
with React.useCallback
because, in every re-render of your component, the function reference changes. Then your effect will be fired for no reason. Put todos
in the dependencies array inside the saveLocalTodos
. You want your function to change only when todos change. Otherwise, you will get stale todos.
Upvotes: 3