Why this would be a violation of the hooks rules.?
In my case:
const getTopicId = useSelector((state) => state.topics.selectTopic.topicId) !== "" ? useSelector((state) => state.topics.selectTopic.topicId) : JSON.parse(localStorage.getItem("topic")).topicId;
I don't put a condition inside the useSelector, i try to say that if useSelector() has data, use it, if not use the localStorage data.
the solution that accept EsLint is: Put the useSelector inside a variable and then inside the ternary....but i don't understant why.
const getTopicSelector = useSelector((state) => state.topics.selectTopic.topicId);
const getTopicId = useSelector((state) => state.topics.selectTopic.topicId) !== "" ? getTopicSelector : JSON.parse(localStorage.getItem("topic")).topicId
Thanks for your explanations.
CodePudding user response:
Your code sometimes calls useSelector
once and sometimes twice.
If you take
const getTopicId = useSelector((state) => state.topics.selectTopic.topicId) !== "" ? useSelector((state) => state.topics.selectTopic.topicId) : JSON.parse(localStorage.getItem("topic")).topicId;
and rewrite the ternary to if..else
, you can see that clearly:
let getTopicId;
const conditionTopicId = useSelector((state) => state.topics.selectTopic.topicId)
if (conditionTopicId !== "") {
getTopicId = useSelector((state) => state.topics.selectTopic.topicId)
} else {
getTopicId = JSON.parse(localStorage.getItem("topic")).topicId
};
Sometimes you call a hook once, sometimes twice. This violates the rules of hooks and will make React crash in the long run.
In your case, you can rewrite that quite simple:
let getTopicId = useSelector((state) => state.topics.selectTopic.topicId)
if (getTopicId == "") {
getTopicId = JSON.parse(localStorage.getItem("topic")).topicId
}
And suddenly you call the hook only once - and you don't do it conditionally.
You can also go with a ternary and put the logic inside one hook call:
const getTopicId = useSelector(
(state) =>
state.topics.selectTopic.topicId !== "" ?
state.topics.selectTopic.topicId :
JSON.parse(localStorage.getItem("topic")).topicId
)
All of these alternatives are fine - the only important thing: don't call useSelector
inside a condition (and a ternary is just a short way of writing if...else
).
React does not allow for that and it will crash on you sooner or later if you do.
CodePudding user response:
useSelector return a certain type which is not compatible with whatever the values sending from the localstorage
Best way to handle this condition is to add a separate useMemo variable
const {selectTopic} = useSelector((state) => state.topics)
const getTopicId = useMemo(() => {
return selectTopic.topicId !== "" ? getTopicSelector : JSON.parse(localStorage.getItem("topic")).topic
}, [selectTopic])