React's key point is 'state', and the 'key' attribute is special and powerful. When a key
changes, React will create a new component instance rather than update the current one, so the useSate
will be called in the component.
First highly recommend reading this post from ReactJS Blog: https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html - it's old article and is not really related to the issue I have, but it explains what ‘key’ attribute is.
Here is a Child Component I have:
Rank.JS
export default function TimeTable({ swimmer }) {
const {season, records} = swimmer;
let defaultSeason = season;
try {
if (records && records.total > 0) {
const mySeason = getSeason(records.data[0].date);
defaultSeason = mySeason.season;
}
} catch (error) {}
const ageGroup = getAgeGroup(rankingAge);
const zone = getZone(lscCode);
const [activeSeason, setActiveSeason] = useState(defaultSeason);
...
}
In the Parent Component I have:
Swimmer.js
import RANK from "./Rank.js";
const Swimmer = (props) => {
....
return(
<Rank swimmer={props.swimmer} />
)
}
So when calling “/swimmer/abc”, it renders <Swimmer> component, which renders <Rank> component, where activeSeason
is state via useState
. Note that activeSeason
is calculated based on the current swimmer (abc.) After that, I call another swimmer “/swimmer/efg”, since it's under the same Router vis Next/Link, so the react only does update the existing Child (i.e., <Rank> component), and something probably very basic, although it still calculates the defaultSeason
for the new swimmer ‘efg’, the state will not be set, because it only happens in a new component (i.e., the first component mount.) Therefore the activeSeason
from the previous swimmer (abc) will be used regarding the new default value.
To fix this, just need to add ‘key’. Another solution could be adding useEffect with the swimmer as a dependency, so when the swimmer changes, set state
by calling setActiveSeason
. I certainly prefer to do this by adding a key:
import RANK from "./Rank.js";
const Swimmer = (props) => {
....
return(
<Rank swimmer={props.swimmer} key={props.swimmer.id} />
)
}