In my project I have some arrow icons (contained in the Skill
component) and when you click on them it changes their className. To check if the component has been clicked I used a boolean array as state, so when the onClick event is fired it toggle the state of the component.
The states change correctly but the component does not update the class and rendering takes place (as well as during mounting) only after the first click.
The page code:
import { useState, useEffect } from 'react';
import Skill from '../../components/skill/skill.component';
import { skills } from './skills';
import './about-page.styles.scss';
const AboutPage = () => {
console.log('render')
const [cache, setCache] = useState([]);
useEffect(() => {
setCache(new Array(skills.length).fill(false))
}, []);
const onToggleFunc = n => {
cache[n] = !cache[n];
setCache(cache);
console.log(cache);
}
return (
<div className='about-page'>
<div className='container'>
{
skills.map((x, i) => (
<Skill
isToggled={cache[i]}
skillName={x.name}
onClickFunc={() => (onToggleFunc(i))}
key={i}
/>
))
}
</div>
</div>
)
}
export default AboutPage;
the Skill component code:
import './skill.styles.scss';
import icon from '../../assets/icons/arrow.png';
const Skill = ({ isToggled, skillName, onClickFunc }) => (
<div className='skill-item'>
<img src={icon} alt='icon'
className={`icon ${isToggled ? 'toggled' : '' }`}
onClick={onClickFunc}
/>
<span className='desc'>{skillName}</span>
</div>
)
export default Skill;
Here the browser console
CodePudding user response:
You must never mutate a state variable, you must instead create a new reference and update the state variable by calling the updater method.
const AboutPage = () => {
const [cache, setCache] = useState(() => new Array(skills.length).fill(false));
function onToggleFunc(n) {
// create a new array from the previous one
setCache(prevCache => prevCache.map((val, i) => i !== n ? val : !val));
}
return (
<div className='about-page'>
<div className='container'>
{
skills.map((x, i) => (
<Skill
key={i}
isToggled={cache[i]}
skillName={x.name}
onClickFunc={() => onToggleFunc(i)}
/>
))
}
</div>
</div>
)
}
export default AboutPage;