React hooks错误:渲染的钩子比上一个渲染期间要多

时间:2020-02-11 02:41:51

标签: javascript reactjs

我以前让功能组件充当页面:

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 => <...>}</>)
}

运行良好,但是最近我需要用NormalList组件包裹ListPage

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

然后突然我收到此错误Rendered more hooks than during the previous render.

在我看来setCreditNotes(data)中的getCreditNoteList引起了错误,但我不知道为什么。

2 个答案:

答案 0 :(得分:2)

因此,您需要修复一些问题。首先,您应该从useState函数中删除函数调用,只应在useEffect挂钩内执行副作用,请参见React Docs

接下来的事情是,每当您决定对useEffect挂钩使用依赖项数组时,都应包括useEffect的所有依赖项,即所有道具,包括在useEffect挂钩中使用的函数组件中的函数。因此,经验法则是从不对自己的依赖性撒谎!,否则,您将被打倒。

因此,最简单的选择是将 getCreditNoteList 函数移到useEffect挂钩中,并将useEffect挂钩的所有依赖项添加到依赖项数组中。


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 (
       <> </>
    )
}

第二个选项 如果要在其他地方使用 getCreditNoteList 函数并将其保留在useEffect挂钩之外,则可以通过将 getCreditNoteList 逻辑包装在useCallback挂钩内,如下所示并添加出于我前面提到的原因,useEffect挂钩中依赖数组的函数。

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 (
       <> </>
    )
}

答案 1 :(得分:0)

好的,我的问题是我在导入元素时遇到两个问题,首先是pycharm巧妙地自动错误地导入了它们,其次我根本没有导入任何一个组件。

我希望错误消息比“比上一次渲染期间渲染更多的钩子”更具体。

我还测试了不需要在getCreditNoteList内移动函数主体useEffect

感谢@ chitova263抽出宝贵时间来提供帮助。