React简单useReducer应用中alert弹窗出现两次是什么原因?
问题根因
你遇到的alert弹窗触发两次是两个问题叠加导致的:
- 违反了
useReducer要求reducer为纯函数的规范:reducer必须是无副作用的纯函数,不能直接编写alert、修改外部变量、发起请求这类副作用逻辑。 - React 18 开发环境严格模式的校验机制:默认开启的严格模式下,React会在开发环境故意重复调用reducer、函数组件体等应该是纯函数的逻辑,用来提前发现不符合纯函数要求的隐藏问题,你的alert属于副作用逻辑,就会跟着重复执行。
当你把数值从1下调到0时,payload的value触发了alert分支,严格模式下reducer被调用两次,自然就弹出两次alert。生产环境下严格模式不会生效,这种写法下alert只会弹一次,但依然不符合React的设计规范,可能会引发其他隐藏问题。
修复方案
把副作用逻辑从reducer中剥离,放到useEffect或者事件回调中执行即可,修改后的参考代码如下:
import "./styles.css"; import { useReducer, useEffect } from "react"; const reducerFunction = (state, action) => { switch (action.type) { case "testing": { if (action.payload.value > 0) { return { ...state, testing: action.payload.value, showAlert: false }; } else { // 仅标记需要触发提示,不执行副作用 return { ...state, showAlert: true }; } } default: { throw new Error("Invalid Action"); } } }; export default function App() { const defaultValue = { testing: 0, showAlert: false }; const [state, dispatch] = useReducer(reducerFunction, defaultValue); // 副作用统一放到useEffect中执行 useEffect(() => { if (state.showAlert) { alert("some message"); // 触发后重置alert标记 dispatch({ type: "testing", payload: { value: 0 } }); } }, [state.showAlert, dispatch]) return ( <input value={state.testing} onChange={(e) => { // 建议先转成数字,避免字符串和数字比较的隐式转换问题 const value = Number(e.target.value) dispatch({ type: "testing", payload: { value } }); }} type="number" /> ); }
内容的提问来源于stack exchange,提问作者Shishir Tiwari
相关产品推荐
相关产品推荐

