Search code examples
reactjsdisabled-input

React input tag disabled prop issue


I am trying to build a login form in React.js. I want to enable/disable Login button based on results return by validate method. React throws error 'Invalid value for prop disabled on tag. Either remove it from the element, or pass a string or number value to keep it in the DOM.'. Does anyone have came across same error? Help me to understand what is going wrong here?

import React, { Component } from "react";
import Input from "../common/input";
import Joi from "joi-browser";

class LoginForm extends Component {
  state = {
    account: {
      username: "",
      password: "",
    },
    errors: {},
  };

  schema = {
    username: Joi.string().required().label("Username"),
    password: Joi.string().required().label("Password"),
  };

  abortEarly = {
    abortEarly: false,
  };

  handleSubmit = (event) => {
    event.preventDefault();
    const errors = this.validate();
    if (errors) return;
    console.log("submitted");
  };

  validate = () => {
    const result = Joi.validate(
      this.state.account,
      this.schema,
      this.abortEarly
    );
    const errors = {};
    if (!result.error) return null;
    result.error.details.map((detail) => {
      errors[detail.path[0]] = detail.message;
      return detail.path[0];
    });
    // console.log(errors);
    this.setState({ errors });
    return errors;
  };

  validateProperty = ({ name, value }) => {
    const propertyTobeValidated = { [name]: value };
    const schema = { [name]: this.schema[name] };
    const { error } = Joi.validate(propertyTobeValidated, schema);
    return error ? error.details[0].message : null;
  };

  handleChange = ({ currentTarget }) => {
    const errors = { ...this.state.errors };
    const error = this.validateProperty(currentTarget);
    if (error) errors[currentTarget.name] = error;
    else delete errors[currentTarget.name];
    const account = { ...this.state.account };
    account[currentTarget.name] = currentTarget.value;
    this.setState({ account, errors });
  };

  render() {
    const { account, errors } = this.state;
    return (
      <div>
        <h1>Login</h1>
        <form onSubmit={this.handleSubmit}>
          <Input
            label="Username"
            name="username"
            value={account.username}
            onChange={this.handleChange}
            error={errors.username}
          ></Input>
          <Input
            label="Password"
            name="password"
            value={account.password}
            onChange={this.handleChange}
            error={errors.password}
          ></Input>

          <button disabled={this.validate} className="btn btn-primary">
            Login
          </button>
        </form>
      </div>
    );
  }
}

export default LoginForm;

Solution

  • Disabled is a boolean property, meaning it can only have a value of true or false. Instead of a boolean, your validate function is returning an object, thus React throws an "Invalid value" error. In order to fix this you could check if the result of this.validate is null:

    <button 
        disabled={(this.validate() !== null)} 
        className="btn btn-primary"
    >
        Login
    </button>
    

    Also, you forgot to call your this.validate at all :)

    Regarding the "Maximum update depth...", you should remove the this.setState from the this.validate, because you are already putting the error in state in the handleChange method.