React中useReducer实现多密码框独立显隐的问题及修复
问题分析与修复方案
问题根源
你的代码核心问题在于用单一全局状态控制两个独立的密码输入框:
- 全局只维护了一组
inputType和isShowPassword状态,没有区分“创建密码”和“确认密码”的独立状态 - 两个输入框都绑定同一个
inputType,任何一个切换按钮触发的action都会修改这组全局值,导致两个输入框同步显示/隐藏
修复方案
我们需要拆分状态,给每个密码输入框分配独立的状态,并让reducer能够精准修改对应输入框的状态。
步骤1:重构状态结构
把默认状态拆分为两个独立的字段,分别对应两个密码输入框:
// 单个密码输入框的状态类型 type PasswordFieldState = { inputType: string; isShowPassword: boolean; }; // 全局状态类型 type StateType = { createPassword: PasswordFieldState; confirmPassword: PasswordFieldState; }; // 初始状态 const defaultState: StateType = { createPassword: { inputType: "password", isShowPassword: false, }, confirmPassword: { inputType: "password", isShowPassword: false, }, };
步骤2:更新Action类型
让action携带目标字段标识,告诉reducer要修改哪个输入框的状态:
type ActionTypes = { type: "SHOW" | "HIDE"; payload: { field: "createPassword" | "confirmPassword"; }; };
步骤3:重写Reducer逻辑
根据action中的field标识,只更新对应输入框的状态,不影响另一个:
const reducerFunction = (state: StateType, action: ActionTypes) => { const { field } = action.payload; switch (action.type) { case "SHOW": return { ...state, [field]: { ...state[field], inputType: "text", isShowPassword: true, }, }; case "HIDE": return { ...state, [field]: { ...state[field], inputType: "password", isShowPassword: false, }, }; default: return state; } };
步骤4:更新组件状态传递与使用
在父组件传递拆分后的状态,子组件分别绑定对应输入框的状态:
const Login = () => { const [state, dispatch] = useReducer(reducerFunction, defaultState); const [isAlreadyMember, setIsAlreadyMember] = useState(true); return ( <section> <div> <Signup dispatch={dispatch} createPasswordState={state.createPassword} confirmPasswordState={state.confirmPassword} setIsAlreadyMember={setIsAlreadyMember} /> </div> </section> ); }; // 更新Signup组件的Props类型 type SignupProps = { dispatch: Dispatch<ActionTypes>; createPasswordState: PasswordFieldState; confirmPasswordState: PasswordFieldState; setIsAlreadyMember: React.Dispatch<React.SetStateAction<boolean>>; }; const Signup = ({ dispatch, createPasswordState, confirmPasswordState, setIsAlreadyMember, }: SignupProps) => { return ( <div> <form action=""> <input type="email" name="email" placeholder="email" /> {/* 创建密码输入框 */} <div> <input type={createPasswordState.inputType} name="password" placeholder="create password" /> {!createPasswordState.isShowPassword ? ( <button onClick={(e) => { e.preventDefault(); dispatch({ type: "SHOW", payload: { field: "createPassword" }, }); }} className="bg-none text-xs absolute right-0 p-3 bottom-0" > Show </button> ) : ( <button onClick={(e) => { e.preventDefault(); dispatch({ type: "HIDE", payload: { field: "createPassword" }, }); }} > Hide </button> )} </div> {/* 确认密码输入框 */} <div> <input type={confirmPasswordState.inputType} name="password" placeholder="reenter password" /> {!confirmPasswordState.isShowPassword ? ( <button onClick={(e) => { e.preventDefault(); dispatch({ type: "SHOW", payload: { field: "confirmPassword" }, }); }} > Show </button> ) : ( <button onClick={(e) => { e.preventDefault(); dispatch({ type: "HIDE", payload: { field: "confirmPassword" }, }); }} > Hide </button> )} </div> <button onClick={(e) => e.preventDefault()} className="primary-btn w-full mt-5" > Sign Up </button> </form> </div> ); };
关键改动说明
- 状态拆分:将单一全局状态拆分为两个独立的状态对象,各自维护自己的显隐状态
- Action精准定位:每个切换操作都明确指定要修改的输入框,避免全局覆盖
- Reducer局部更新:只修改目标输入框的状态,不影响另一个输入框的原有状态
内容的提问来源于stack exchange,提问作者cris
相关产品推荐
相关产品推荐

