使用useReducer+Context管理登录组件状态,输入框无响应问题求助
输入框无响应:useContext + useReducer 管理登录状态异常
我在createContext文件中引入useReducer,希望通过useContext管理所有用户输入,验证输入后更新状态,但登录组件的输入框对任何按键操作都无响应。
reducer-context.js 代码
import React, { useReducer } from "react"; // 上下文定义 const ValContext = React.createContext({ email: "", eValid: null, onChangeEmail: (e) => {}, onEmailIsValid: () => {}, password: "", pValid: null, onChangePassword: (e) => {}, onPasswordIsValid: () => {}, }); // 初始状态 export const INITIAL_STATE = { email: "", eValid: null, password: "", pValid: null, }; // reducer函数 const reducer = (state = INITIAL_STATE, actions) => { switch (actions.type) { case "EMAIL_INPUT": return { ...state, email: actions.payload, eValid: actions.payload.trim().includes("@"), }; case "EMAIL_BLUR": return { ...state, email: state.email, eValid: state.email.trim().includes("@"), }; case "PASSWORD_INPUT": return { ...state, password: actions.payload, pValid: actions.payload.trim().length >= 6, }; case "PASSWORD_BLUR": return { ...state, password: state.password, pValid: state.password.trim().length >= 6, }; default: return state; } }; // 上下文Provider组件 export const Validation = (props) => { const [state, dispatch] = useReducer(reducer, { email: "", eValid: null, password: "", pValid: null, }); console.log(state); const emailChangeHandler = (email) => { dispatch({ type: "EMAIL_INPUT", payload: email }); }; const passwordChangeHandler = (e) => { dispatch({ type: "PASSWORD_INPUT", payload: e.target.value }); }; const emailValidation = (e) => { dispatch({ type: "EMAIL_BLUR" }); }; const passwordValidation = (e) => { dispatch({ type: "PASSWORD_BLUR" }); }; return ( <ValContext.Provider value={{ email: state.email, eValid: state.eValid, onChangeEmail: (e) => emailChangeHandler(e), onEmailIsValid: emailValidation, password: state.password, pValid: state.pValid, onChangePassword: passwordChangeHandler, onPasswordIsValid: passwordValidation, }} > {props.children} </ValContext.Provider> ); }; export default ValContext;
Login.js 代码
import React, { useContext, useState, useEffect } from "react"; import Card from "../UI/Card/Card"; import classes from "./Login.module.css"; import Button from "../UI/Button/Button"; import AuthContext from "../../store/auth-context"; import ValContext, { Validation } from "../../store/reducer-context"; const Login = (props) => { const [formIsValid, setFormIsValid] = useState(false); const authCtx = useContext(AuthContext); // 获取状态上下文 const valCtx = useContext(ValContext); useEffect(() => { setFormIsValid(valCtx.eValid && valCtx.pValid); }, [valCtx.eValid, valCtx.pValid]); const submitHandler = (event) => { event.preventDefault(); authCtx.onLogin(valCtx.email, valCtx.password); }; return ( <Validation> <Card className={classes.login}> <form onSubmit={submitHandler}> <div className={`${classes.control} ${ valCtx.eValid === false ? classes.invalid : "" }`} > <label htmlFor="email">E-Mail</label> <input type="email" id="email" value={valCtx.email} onChange={valCtx.onChangeEmail} onBlur={valCtx.onEmailIsValid} /> </div> <div className={`${classes.control} ${ valCtx.pValid === false ? classes.invalid : "" }`} > <label htmlFor="password">Password</label> <input type="password" id="password" value={valCtx.password} onChange={valCtx.onChangePassword} onBlur={valCtx.onPasswordIsValid} /> </div> <div className={classes.actions}> <Button type="submit" className={classes.btn} disabled={!formIsValid} > Login </Button> </div> </form> </Card> </Validation> ); }; export default Login;
问题原因及修复方案
1. 上下文Provider嵌套错误
Login组件内部直接包裹了<Validation>(上下文Provider),导致:
- 每次Login组件渲染时,都会创建新的Provider实例,上下文状态被重复初始化
useContext(ValContext)获取的是外层默认上下文(不是内部Provider提供的状态),输入框绑定的是默认值,自然无法响应更新
修复:
将<Validation>移到Login组件的外层(比如App.js中),确保上下文作用域覆盖Login组件:
// App.js示例 import Login from './components/Login'; import { Validation } from './store/reducer-context'; function App() { return ( <Validation> <Login /> </Validation> ); }
同时修改Login组件,移除内部的<Validation>包裹:
// Login.js中修改return部分 return ( <Card className={classes.login}> <form onSubmit={submitHandler}> {/* 原有表单内容保持不变 */} </form> </Card> );
2. 邮箱变更处理函数参数错误
emailChangeHandler定义为接收email参数,但onChangeEmail传递的是事件对象e,导致actions.payload是事件对象而非输入值,邮箱状态无法正确更新。
修复:
修改reducer-context.js中的emailChangeHandler,改为接收事件对象并取输入值:
const emailChangeHandler = (e) => { dispatch({ type: "EMAIL_INPUT", payload: e.target.value }); };
同时简化Provider中的onChangeEmail绑定,直接传递函数即可:
// ValContext.Provider的value中修改 onChangeEmail: emailChangeHandler,
内容的提问来源于stack exchange,提问作者A. Lawal
相关产品推荐
相关产品推荐

