I have a personal hook which is used to manage a list of counters:
import { useEffect, useState } from "react";
import { db } from "../services/database";
const useCounters = () => {
const [counters, setCounters] = useState([]);
console.log("Hook", counters);
const addCounter = async (newCounter) => {
try {
await db.cards.add(newCounter);
setCounters((prevState) => [...prevState, newCounter]);
} catch (error) {
console.error(error);
}
};
const removeCounter = async (idToRemove) => {
try {
await db.cards.delete(idToRemove);
setCounters(counters.filter((counter) => counter.id !== idToRemove));
} catch (error) {
console.error(error);
}
};
const updateCounter = async (idToUpdate, newValue) => {
try {
await db.cards.update(idToUpdate, { value: newValue });
} catch (error) {
console.error(error);
}
};
useEffect(() => {
const loadData = async () => {
db.cards.toArray().then((cards) => {
setCounters(cards);
});
};
loadData();
}, []);
return {
counters,
addCounter,
removeCounter,
updateCounter,
};
};
export default useCounters;
And I have an element that is responsible for rendering these counters:
import Counter from "../components/Counter";
import AddCounter from "../components/AddCounter.js";
import Sleep from "../components/Sleep";
import useCounters from "../Hooks/useCounters";
import Style from "../css/pages/cards.module.css";
const Cards = () => {
const { counters } = useCounters();
console.log("Cards", counters);
return (
<div className={Style.cards}>
{counters.map((item) => (
<Counter
key={item.id}
id={item.id}
title={item.title}
initial={item.initialValue}
value={item.value}
color={item.color}
/>
))}
<AddCounter />
<Sleep />
</div>
);
};
export default Cards;
My problem is that when using the methods that manipulate the counters, it updates the state of the counters, but it does not render this in the cards component. Can someone explain to me what is happening and how to fix?
--
I tried to put 'counters' as a useEffect dependency but this generates an infinite rendering (eternal loop).
useEffect(() => {
const loadData = async () => {
db.cards.toArray().then((cards) => {
setCounters(cards);
});
};
loadData();
}, [counters]);
What happens here is that your counters
state is not a global state, but a local state in every component that uses your hook.
For example: If you use the hook in Cards
and in AddCounter
both components have a local version of that state. If you add a counter in AddCounter
the counters
variable there will change, but not in the Cards
component. Have a look at this sandbox to see this behaviour.
If you want to share your state between components, there are several ways: