简体   繁体   中英

React hooks error: Rendered more hooks than during the previous render

I used to have a function component act as a page:

export default function NormalList(props) {
    const pageSize = 20;
    const [page, setPage] = useState(1)
    const [searchString, setSearchString] = useState(null);
    const [creditNotes, setCreditNotes] = useState(() => getCreditNoteList());
    const [ordering, setOrdering] = useState(null);

    useEffect(() => getCreditNoteList(), [page, searchString, ordering]);

    function getCreditNoteList() {
        API.fetchCreditNoteList({
            account_id: props.customerId, page, page_size: pageSize, searchString, ordering
        }).then(data => {
            setCreditNotes(data);
        });
    }
    return (<>{creditNotes.results.map(record => <...>}</>)
}

And this has been running fine, but recently I need to wrap around NormalList with ListPage component:

export default function ListPage(props) {
    const customerId = props.match.params.customer_id;
    return (<div>...<div><NormalList/></div></div>)
}

Then all the sudden I am getting this error Rendered more hooks than during the previous render.

It seems to me that setCreditNotes(data) inside getCreditNoteList is causing the error, but I don't know why.

So there are a couple of things you need to fix. First of all you should remove your function call from the useState function, you should only perform your side effects inside a useEffect hook see React Docs .

The next thing is whenever you decide to use the dependency array to your useEffect hook you should include all the dependencies of useEffect ie all the props, state including functions inside your function component that you used inside your useEffect hook. So the Rule of Thumb is Never Lie About Your Dependencies! otherwise you will shoot yourself in the foot.

So the easiest option is to move your getCreditNoteList function inside your useEffect hook and add all the dependencies of your useEffect hook to the dependency array.


export default function NormalList({ customerId }) {
    const pageSize = 20;
    const [page, setPage] = useState(1)
    const [searchString, setSearchString] = useState(null);
    const [creditNotes, setCreditNotes] = useState({});
    const [ordering, setOrdering] = useState(null);

    useEffect(() => {

      function getCreditNoteList() {
        API.fetchCreditNoteList({
            account_id: customerId, 
            page, 
            page_size: pageSize, 
            searchString, 
            ordering
        }).then(data => {
            setCreditNotes(data);
        });
      }

      getCreditNoteList(),

       // add ALL! dependencies
    }, [page, searchString, ordering, pageSize, customerId]))

    return (
       <> </>
    )
}

Second Option If you want to use the getCreditNoteList function elsewhere and want to keep it outside your useEffect hook you can do that by wrapping your getCreditNoteList logic inside the useCallback hook as shown below and add the function to your dependency array inside your useEffect hook for reasons i mentioned earlier.

export default function NormalList({ customerId }) {
    const pageSize = 20;
    const [page, setPage] = useState(1)
    const [searchString, setSearchString] = useState(null);
    const [creditNotes, setCreditNotes] = useState({});
    const [ordering, setOrdering] = useState(null);

    const getCreditNoteList = useCallback(() => {
        API.fetchCreditNoteList({
            account_id: customerId, 
            page, 
            page_size: pageSize, 
            searchString, 
            ordering
        }).then(data => {
            setCreditNotes(data);
        });
     // the function only changes when any of these dependencies change
    },[page, searchString, ordering, pageSize, customerId])

    useEffect(() => {

      getCreditNoteList(),

    },[getCreditNoteList])

    return (
       <> </>
    )
}

OK My problem was that I had 2 issues with importing the elements, first being pycharm cleverly automatically imported them wrong, and secondly being I didn't import one of the component at all.

I wish the error message could be a bit more specific than "Rendered more hooks than during the previous render".

Also I tested I didn't need to move function body getCreditNoteList inside useEffect .

Thanks to @chitova263 for spending the time to help out.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM