0

I have a component that dispatches some actions when a state somewhere else in the app changes. But this is somehow giving me the dreaded change in the order of Hooks error.

In reading the rules of hooks it says basically wrapping hooks in conditionals is verboten... Which I am not currently doing.

However I am rendering lists of items and the values of those lists changes, as the server loads data. Using selectors and redux-sagas makes all of this pretty impossible to actually debug, so how else might I track down the root of the problem?

I have one component:

const PhraseList = props => {
    const trainingPhrases = useSelector(selectFilteredPhrases());

    return (
        <div className={styles.Wrapper}>
            <ul className={opStyles.listReset}>
                {  
                    trainingPhrases.map((phrase, idx) => {
                        return PhraseItem({ phrase, idx });
                    })
                }
            </ul>
        </div>
    );

which calls the PhraseItem component, which throws an Error.

const PhraseItem = ({ phrase, idx }) => {
    // this line chokes
    const [checked, setChecked] = useState(false);

    return (
        <li key={"tr-" + idx}>
            <div className={styles.container}>
                <div className={styles.phraseText}>{phrase.text}</div>
            </div>
        </li>
    );
};

I'm debugging changes in the selector (selector factory) and that is what seems to trigger the app to crash.

export const selectFilteredPhrases = () =>
    createSelector(trainingPhrases, phraseFilter, (trainingPhrases, phraseFilter) => {
        console.log('trainingPhrases', trainingPhrases)
        return trainingPhrases
    });

but if data didn't change ever, it's hard to buidl an app :O

I saw an answer about using JSX which I don't think is relevant. And not much else on this issue.

redux, sagas, hooks, selectors... the react DSL is more and more layers and it's hard to debug deep in the framework.

UPDATE. I think this might be because I'm calling two sagas one after the other and this causes some kind of race condition in the UI?

    const pickIntent = () => {
        dispatch(pickIntentAction(intentId));
        dispatch(getIntentPhrasesAction(intentId));

debuglog

dcsan
  • 11,333
  • 15
  • 77
  • 118
  • 2
    Can you test something for me: replace `return PhraseItem({ phrase, idx });` with `return ;` – david Mar 24 '20 at 00:01
  • @david I owe you a beer! The answer was staring me in the face. Thanks so much! The difference between JSX and JS is sometimes not noticeable... – dcsan Mar 24 '20 at 00:46

1 Answers1

0

I think this answer is related, as it is already mentioned in this link, if you call the jsx component as a function react thinks that, hooks which are declared in this jsx function is part of the app component, so if your array trainingPhrases has fewer element on the first render than on the second one it will cause this warning (there will be less rendered jsx components, which means there will be less hooks). solution is simple call jsx component like this <PhraseItem phrase={phrase} idx={idx} />