使用自定义钩子时如何停止重新渲染(超出最大深度)

问题描述 投票:0回答:1

我有一个 React 项目,我试图通过将逻辑移动到钩子来将逻辑与 UI 分开。所讨论的钩子从 RTK 查询收集分页数据并将其聚合到状态变量

transactions
中。如果我将Transactions 设置为这个聚合,则不会有问题,但如果我尝试以任何方式更改它,我会看到组件重新渲染多次,从而导致最大深度超出错误。

我已将这个问题提炼为最基本的要素,删除了 UI 和所有不会导致错误的逻辑。

AccountTransactions 组件:

export default function AccountTransactions() {
    const { transactions, handleMoreTransactionsClick, handleDeleteTransaction } = useTransactions(68);
    console.log('transactions', transactions); // I see this log many times

    return (
        <div></div>
    );
}

TransactionsHook 自定义挂钩:

export default function useTransactions (accountId) {
    const [page, setPage] = useState(1);
    const [transactions, setTransactions] = useState([]);

    // load transactions
    const {
        data = [],
        isSuccess,
    } = useGetTransactionsQuery({accountId: accountId, page: page});

    useEffect(() => {
        // setTransactions(transactions); // this doesn't cause rerenders 
        setTransactions([]); // this causes rerenders
    }, [data]);

    return { transactions };
}

我使用

data
作为钩子 useEffect 的依赖项,因为
isLoading
在加载第一页后保持 true,并且后续页面不会加载。但是,使用
data
作为依赖项并更改
transactions
的某种组合会触发组件的重新渲染。让我更困惑的是,在这个简化代码中,
transactions
[]
,但为其分配新值
[]
也会导致重新渲染。

为了完整起见,这里是 RTK 减速器,尽管我不认为这会导致问题。

        getTransactions: build.query({
            query: ({accountId, page}) => ({
                url: `/api/transactions/account/${accountId}`,
                method: 'get',
                params: {page}
            }),
            providesTags: (result = [], error, arg) => [
                'Transaction',
                ...result.data.map(({ id }) => ({ type: 'Transaction', id })),
            ],
        }),

我仍然在思考钩子(甚至渲染过程),但我看不出我是如何违反任何规则的。其他人能发现什么吗?

reactjs react-hooks
1个回答
0
投票

setTransactions(transactions);
不会导致渲染,因为先前状态
transactions
和新状态
transactions
是相同的对象(相同的对象引用)。因此,钩子
useGetTransactionsQuery
仅调用一次。

setTransactions([])
导致渲染循环,因为
[]
创建了新对象(状态更改),这导致渲染,这导致
useGetTransactionsQuery
钩子调用,这改变了
data
并导致效果。

© www.soinside.com 2019 - 2024. All rights reserved.