javascript - 验证 render() 中使用的状态变量以设计/填充 html

标签 javascript reactjs

我有以下 React 组件,它包含一个带有两个输入和一个按钮的表单。

export default class Login extends Component {
    constructor(props) {
        super(props);
        this.state = {
            email: null,
            password: null
        }
    }

    emailInputChanged = (e) => {
        this.setState({
            email: e.target.value.trim()
        });
    };
    passwordInputChanged = (e) => {
        this.setState({
            password: e.target.value.trim()
        });
    };

    loginButtonClicked = (e) => {
        e.preventDefault();
        if (!this.isFormValid()) {
            //Perform some API request to validate data
        }
    };

    signupButtonClicked = (e) => {
        e.preventDefault();
        this.props.history.push('/signup');
    };

    forgotPasswordButtonClicked = (e) => {
        e.preventDefault();
        this.props.history.push('/forgot-password');
    };


    isFormValid = () => {
        const {email, password} = this.state;
        if (email === null || password === null) {
            return false;
        }

        return isValidEmail(email) && password.length > 0;
    };

    render() {
        const {email, password} = this.state;
        return (
            <div id="login">
                <h1 className="title">Login</h1>
                <form action="">
                    <div className={(!isValidEmail(email) ? 'has-error' : '') + ' input-holder'}>
                        <Label htmlFor={'loginEmail'} hidden={email !== null && email.length > 0}>email</Label>
                        <input type="text" className="input" id="loginEmail" value={email !== null ? email : ''}
                               onChange={this.emailInputChanged}/>
                    </div>
                    <div className={(password !== null && password.length === 0 ? 'has-error' : '') + ' input-holder'}>
                        <Label htmlFor={'loginPassword'}
                               hidden={password !== null && password.length > 0}>password</Label>
                        <input type="password" className="input" id="loginPassword"
                               value={password !== null ? password : ''}
                               onChange={this.passwordInputChanged}/>
                    </div>
                    <button type="submit" className="btn btn-default" id="loginButton"
                            onClick={this.loginButtonClicked}>
                        login
                    </button>
                </form>
                <div className="utilities">
                    <a href={'/signup'} onClick={this.signupButtonClicked}>don't have an account?</a>
                    <a href={'/forgot-password'} onClick={this.forgotPasswordButtonClicked}>forgot your password?</a>
                </div>
            </div>
        )
    }
}

export function isValidEmail(email) {
    const expression = /\S+@\S+/;
    return expression.test(String(email).toLowerCase());
}

输入的值存储在组件的 state 中。我给了它们初始值 null并使用 setState() 更新它们在 onChange事件。

render()方法我使用状态为具有无效值的输入着色。目前,我仅根据简单的正则表达式检查电子邮件值,并且密码长度至少为 1 个字符。

我将状态变量的初始值设置为 null 的原因所以我可以检查输入的布局和初始样式,使其不被标记为 "has-errors" 。但是我需要将检查扩展到:

this.state.email !== null && this.state.email.length === 0

为了工作,因为 null 没有 length属性。

是否有一种更干净且“React-ish”的方式来实现这一目标: - 保存输入的 div 的初始状态没有类 has-errors - 设置 value 时检查较少输入上的属性(因为 React 不接受 null 作为属性值)

<小时/> 编辑: 如果初始值为this.state.emailthis.state.password是空字符串,我得到 has-error应用于保存输入的 div。在我看来,这是糟糕的用户体验,因为用户没有做任何事情,而且他已经错了

hidden属性由我制作的自定义组件使用,其作用类似于“占位符”(如果在输入中键入某些内容,则会被删除)。

下面的视频显示了当 this.state.email 时我的表单的样子和this.state.password也是空字符串以及我的<Label>组件工作原理:

enter image description here

最佳答案

您可以创建一个验证函数,该函数返回一个错误对象以了解哪些字段出现错误,并使用空字符串作为初始值。我不明白你想用隐藏属性做什么。

编辑:在状态中添加触摸属性,以了解哪个字段被触摸。

export default class Login extends Component {
  constructor(props) {
    super(props);
    this.state = {
      email: '',
      password: '',
      touched: {},
    };
  }

  emailInputChanged = e => {
    this.setState({
      email: e.target.value.trim(),
      touched: {
        ...this.state.touched,
        email: true,
      },
    });
  };

  passwordInputChanged = e => {
    this.setState({
      password: e.target.value.trim(),
      touched: {
        ...this.state.touched,
        password: true,
      },
    });
  };

  loginButtonClicked = e => {
    e.preventDefault();
    if (!this.isFormValid()) {
      //Perform some API request to validate data
    }
  };

  isFormValid = () => {
    const errors = this.validate();

    return Object.keys(errors).length === 0;
  };

  validate = () => {
    const errors = {};
    const { email, password } = this.state;

    if (!isValidEmail(email)) {
      errors.email = true;
    }

    if (password.length === 0) {
      errors.password = true;
    }

    return errors;
  };

  render() {
    const { email, password, touched } = this.state;
    const errors = this.validate();

    return (
      <div id="login">
        <h1 className="title">Login</h1>
        <form action="">
          <div
            className={
              (errors.email && touched.email ? 'has-error' : '') +
              ' input-holder'
            }
          >
            <Label htmlFor={'loginEmail'}>email</Label>
            <input
              type="text"
              className="input"
              id="loginEmail"
              value={email}
              onChange={this.emailInputChanged}
            />
          </div>
          <div
            className={
              (errors.password && touched.password ? 'has-error' : '') +
              ' input-holder'
            }
          >
            <Label htmlFor={'loginPassword'}>password</Label>
            <input
              type="password"
              className="input"
              id="loginPassword"
              value={password}
              onChange={this.passwordInputChanged}
            />
          </div>
          <button
            type="submit"
            className="btn btn-default"
            id="loginButton"
            onClick={this.loginButtonClicked}
          >
            login
          </button>
        </form>
      </div>
    );
  }
}

export function isValidEmail(email) {
  const expression = /\S+@\S+/;
  return expression.test(String(email).toLowerCase());
}

关于javascript - 验证 render() 中使用的状态变量以设计/填充 html,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57308655/

相关文章:

javascript - 使用 ReactJS 时更新不相关组件的 DOM

reactjs - 如何将 MSAL 与 React 结合使用?

javascript - 尝试使用 useEffect Hook 来实现此功能

javascript - 不变违规 : findComponentRoot when using Link & Tables

java - Nashorn 中的评估函数是否可从不同线程重用?

javascript - 为什么 $.post 不执行任何操作?

javascript - 如何通过JS更改<select>中当前选定的选项

javascript - Jquery .each() 不添加总和

javascript - 何时将 'classes' 与 'className' 与 Material UI 一起使用?

javascript - Reactjs触发onClick函数而不点击功能组件