I am trying to do my first React build before publishing and running into React Hook errors like this: "React Hook useEffect has missing dependencies: 'colors' and 'options'. Either include them or remove the dependency array.
My component is showing the error on the last line. What am I doing wrong?
function MemoryGame({ options, setOptions, highScore, setHighScore }) {
const [game, setGame] = useState([]);
const [flippedCount, setFlippedCount] = useState(0);
const [flippedIndexes, setFlippedIndexes] = useState([]);
const colors = [
`url(${Background1})`,
`url(${Background13})`,
`url(${Background3})`,
`url(${Background4})`,
`url(${Background5})`,
`url(${Background6})`,
`url(${Background7})`,
`url(${Background8})`,
`url(${Background9})`,
`url(${Background14})`,
`url(${Background11})`,
`url(${Background12})`,
];
useEffect(() => {
const newGame = [];
for (let i = 0; i < options / 2; i++) {
const firstOption = {
id: 2 * i,
colorId: i,
color: colors[i],
flipped: false,
};
const secondOption = {
id: 2 * i + 1,
colorId: i,
color: colors[i],
flipped: false,
};
newGame.push(firstOption);
newGame.push(secondOption);
}
const shuffledGame = newGame.sort(() => Math.random() - 0.5);
setGame(shuffledGame);
}, []);
I just added the [colors, options] but am now getting this: The 'colors' array makes the dependencies of useEffect Hook (at line 137) change on every render. Move it inside the useEffect callback. Alternatively, wrap the initialization of 'colors' in its own useMemo() Hook.
Now I tried moving the const colorsin useEffect and am getting undefined. What am I still doing wrong?
useEffect(() => {
const colors = [
`url(${Background1})`,
`url(${Background13})`,
`url(${Background3})`,
`url(${Background4})`,
`url(${Background5})`,
`url(${Background6})`,
`url(${Background7})`,
`url(${Background8})`,
`url(${Background9})`,
`url(${Background14})`,
`url(${Background11})`,
`url(${Background12})`,
];
const newGame = [];
for (let i = 0; i < options / 2; i++) {
const firstOption = {
id: 2 * i,
colorId: i,
color: colors[i],
flipped: false,
};
const secondOption = {
id: 2 * i + 1,
colorId: i,
color: colors[i],
flipped: false,
};
newGame.push(firstOption);
newGame.push(secondOption);
}
const shuffledGame = newGame.sort(() => Math.random() - 0.5);
setGame(shuffledGame);
}, [colors, options]);
Don't ignore the warning, it is there for a very good reason. The point of it is to inform you that you're using references to variables defined outside of the hook itself that may mutate and leave you with a stale state.
The useEffect hook accepts 2 parameters, the second of which is a dependency array - an empty one in your case. Based on this array react knows when the callback in the useEffect should be executed. Supplying an empty array as in your case will result in the callback running only once, after the initial rendering of the component and won't run anymore, no matter what changes in your component. Thus, even if you change your colors and options references, the hook won't execute and you're gonna be left with a stale state, hence the warning. Your code, however, actually depends on those 2 references, so you should put them in the dependency array as to instruct react to rerun the callback function whenever either of them changes(even if they're constants and you know won't change). So, use this:
useEffect(() => {
const newGame = [];
for (let i = 0; i < options / 2; i++) {
const firstOption = {
id: 2 * i,
colorId: i,
color: colors[i],
flipped: false,
};
const secondOption = {
id: 2 * i + 1,
colorId: i,
color: colors[i],
flipped: false,
};
newGame.push(firstOption);
newGame.push(secondOption);
}
const shuffledGame = newGame.sort(() => Math.random() - 0.5);
setGame(shuffledGame);
}, [colors, options]);
Basically, if a variable(including functions) is used only in the useEffect callback, you should define it inside and you can skip adding it to the dependency array, as it can track it internally.
In the rare cases when you depend only on the initial state of a variable(which can mutate after) for the useEffect and you want to run the hook only once on component 'setup', you should skip adding it to the dependency array and it won't cause it to re-execute.
This is your es-lint warning you that it thinks you're missing these items in your dependency array. It's important to note that this is only showing an error because you have your IDE setup to fail compilation on linting error.
My experience with this rule is that its wildly inconsistent. For example: sometimes you want a useEffect to fire based on certain conditions, but not on others. If one of those parameters happens to be changed as a result of that trigger, (ie. mutated inside the useEffect), you will get this es-lint warning.
My suggestions: change your IDE settings such that this warning will still allow you to compile. This can be changed by modifying the rule in your eslint config. Whenever you see this warning, double check to make sure your useEffect is behaving in a correct manner and you aren't actually missing any dependencies. If this is the case, add an es-lint ignore on top of the useEffect hook.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With