React自定义Hook调用报Too many re-renders无限重渲染错误如何解决?
问题原因
你出现无限重渲染的核心原因是在组件渲染阶段直接执行了触发Redux状态更新的方法:
在SignInPage组件里,你写了const toggle = togglePassVisibility(),这行代码会在组件每次渲染时直接调用togglePassVisibility方法,方法内部调用dispatch修改Redux的toggle状态,状态更新后触发组件重新渲染,新的渲染又会再次执行togglePassVisibility,最终形成无限循环触发重渲染的问题。
错误修复方案
你只需要去掉渲染阶段的直接调用即可,把方法绑定到需要触发的交互事件上,比如你要做密码显隐切换,就绑定到密码输入框旁的眼睛图标点击事件上:
const SignInPage = () => { const { togglePassVisibility } = useToggle(); // 删掉直接调用的 const toggle = togglePassVisibility() 这行 // 示例用法:<button onClick={togglePassVisibility}>切换密码显隐</button> return ( // 原有组件代码不变,需要触发切换的位置绑定onClick事件即可 ) }
结合Redux的自定义Hook优化方案
当前的Hook可以做这几个优化点:
- 优化toggle逻辑:Redux的toggle reducer不需要接收当前的showpass参数,直接在reducer里对状态取反即可,减少Hook对Redux状态的依赖
- 用
useCallback包裹dispatch方法,避免不必要的函数重建,减少子组件重渲染的可能 - 同时返回当前的showpass状态,方便业务组件直接使用,不需要再单独调用
useSelector
优化后的Hook代码:
import { useDispatch, useSelector } from "react-redux"; import { toggle } from "../state/reducers/togglePassSlice"; import { useCallback } from "react"; const useToggle = () => { const showpass = useSelector((state) => state.toggle.showpass); const dispatch = useDispatch(); const togglePassVisibility = useCallback(() => { dispatch(toggle()); }, [dispatch]); return { showpass, togglePassVisibility }; }; export default useToggle;
对应的togglePassSlice里的reducer调整为:
import { createSlice } from "@reduxjs/toolkit"; const togglePassSlice = createSlice({ name: 'toggle', initialState: { showpass: false }, reducers: { toggle: (state) => { state.showpass = !state.showpass; } } }) export const { toggle } = togglePassSlice.actions; export default togglePassSlice.reducer;
优化后业务组件可以直接获取showpass状态控制输入框的type:
// 业务组件用法 const { showpass, togglePassVisibility } = useToggle(); // Input组件动态绑定type <Input type={showpass ? "text" : "password"} placeholder="Enter password" id="password" /> // 切换按钮绑定事件 <button onClick={togglePassVisibility}>{showpass ? '隐藏' : '显示'}密码</button>
内容的提问来源于stack exchange,提问作者Daniel Nduka
相关产品推荐
相关产品推荐

