You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MVP模式下React Hooks登录模块错误传递与展示问题求助

在React MVP模式下实现Presenter向View传递错误信息并展示的正确方式

问题描述

我正在开发应用的登录视图,采用MVP(Model-View-Presenter)模式,想在Presenter中捕获错误,再将其作为props传递给View并在View中处理展示,但遇到了问题。

第一个方案(不符合MVP规范)

直接在Presenter中操作DOM处理错误,虽然能运行但违反MVP规则:

try {await props.model.signIn(email, password)
}
catch (error) {
var errorMessage = error.message;
if (errorMessage.includes("password")) {
document.getElementById("error").innerHTML = "Wrong password, try again"}

第二个方案(遇到props.error未定义问题)

尝试用React State Hooks处理,但View中提示props.error未定义,相关代码如下:

Presenter代码(Login.js)

import LoginView from "../views/loginView";
import React from "react";
function Login(props) {
const [error,setError] = React.useState('') 

async function handleLoginACB() {
        var email = document.getElementById('email').value
        var password = document.getElementById('password').value
        try {
            await props.model.signIn(email, password)
        } catch (error) {
            console.log(error.message)
            setError(error)
            
          
        }

        if (props.model.currentUser != null) {
            window.location.hash = "#HomeScreen"
        }

    }

    return <LoginView onUserLogIn={handleLoginACB} error = {error} />
}

export default Login;

View代码(LoginView.js)

function LoginView(props) {


    return( <div className="loginBox">
    <img src="logo.svg" className="image blob"/>
        <form>
        <input type = "email" placeholder = "Email" id="email"></input> 
        <div><input type = "password" placeholder = "Password" id="password"></input></div>
        <div id = "error">{errorHandling}</div>
        <a href="#CreateAccount">Create a new account</a>
        
        </form>
        <button  onClick={props.onUserLogIn}>Log in</button>
</div>);

function errorHandling(){
    
    console.log(props.error.message)
    if (props.error.message.includes("password")) {
        return "Wrong password, try again"
      }

      if (props.error.message.includes("email")) {
          return "Wrong email, try again"
      }
}


}

export default LoginView;

解决方案

1. 修复初始状态类型不匹配问题

Presenter中初始状态设为空字符串'',但后续赋值的是Error对象,导致初始时props.error是字符串,调用.message会报错。修改初始状态为null:

const [error, setError] = React.useState(null);

2. 调用errorHandling函数(而非引用函数)

View中渲染错误的地方,要调用函数而不是只写函数名,否则不会执行:

<div id="error">{errorHandling()}</div>

3. 添加错误存在的判断,避免空值报错

在errorHandling函数中先判断props.error是否存在,再访问.message:

function errorHandling(){
    if (!props.error) return '';
    
    if (props.error.message.includes("password")) {
        return "Wrong password, try again";
    }

    if (props.error.message.includes("email")) {
        return "Wrong email, try again";
    }
    return '';
}

4. 优化:Presenter不要直接操作DOM(符合MVP规范)

当前Presenter中通过document.getElementById获取输入值,这违反了MVP原则(Presenter不应直接操作View的DOM)。应该让View管理输入状态,将值传递给Presenter:

修改后的LoginView.js(管理输入状态)

import React, { useState } from "react";

function LoginView(props) {
    const [email, setEmail] = useState('');
    const [password, setPassword] = useState('');

    const handleLogin = () => {
        props.onUserLogIn(email, password);
    };

    function errorHandling(){
        if (!props.error) return '';
        
        if (props.error.message.includes("password")) {
            return "Wrong password, try again";
        }

        if (props.error.message.includes("email")) {
            return "Wrong email, try again";
        }
        return '';
    }

    return( <div className="loginBox">
        <img src="logo.svg" className="image blob"/>
        <form>
            <input 
                type="email" 
                placeholder="Email" 
                value={email}
                onChange={(e) => setEmail(e.target.value)}
            /> 
            <div>
                <input 
                    type="password" 
                    placeholder="Password" 
                    value={password}
                    onChange={(e) => setPassword(e.target.value)}
                />
            </div>
            <div id="error">{errorHandling()}</div>
            <a href="#CreateAccount">Create a new account</a>
        </form>
        <button onClick={handleLogin}>Log in</button>
    </div>);
}

export default LoginView;

修改后的Login.js(Presenter接收参数)

import LoginView from "../views/loginView";
import React, { useState } from "react";

function Login(props) {
    const [error, setError] = useState(null);

    async function handleLoginACB(email, password) {
        try {
            await props.model.signIn(email, password);
            if (props.model.currentUser != null) {
                window.location.hash = "#HomeScreen";
            }
            setError(null); // 登录成功后清空错误
        } catch (error) {
            console.log(error.message);
            setError(error);
        }
    }

    return <LoginView onUserLogIn={handleLoginACB} error={error} />;
}

export default Login;

5. 额外优化:路由跳转用React Router(如果使用)

如果项目中使用React Router,建议用useNavigate代替window.location.hash,更符合React生态:

import { useNavigate } from 'react-router-dom';

function Login(props) {
    const navigate = useNavigate();
    // ...
    async function handleLoginACB(email, password) {
        try {
            await props.model.signIn(email, password);
            if (props.model.currentUser != null) {
                navigate("/HomeScreen");
            }
            // ...
        }
        // ...
    }
}

内容的提问来源于stack exchange,提问作者overlythinking

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 21:50:24