0

I am having an issue resetting the errorText to it's original state. Every time the form is submitted with an error(s) it adds all of the errors to the end even if they are from a previous submit.

1st click on blank form // I expect this result every time.

"Errors: Email is invalid. Password is invalid."

2nd click on blank form

"Errors: Email is invalid. Password is invalid. Email is invalid. Password is invalid."

Code Snippet

class LoginForm extends Component {
constructor(props) {
  super(props)
  this.state = {
    details: {
      email: '',
      password: '',
    },
    hasError: false,
    errorText: 'Errors: \n',
  }
}

render() {
  let { hasError, errorText } = this.state
  const { LogUserIn } = this.props

  const onTapLogin = e => {

     // broken?
    if (hasError) {
      this.setState({
        hasError: false,
        errorText: 'Errors: \n',
      })
    }

    if (!check.emailValid(e.email)){
      this.setState({ 
        hasError: true,
        errorText: errorText += "\n - Email address is invalid. "
      })
    }

    if (!check.passwordValid(e.password)){
      this.setState({ 
        hasError: true,
        errorText: errorText += "\n- Password is invalid. "
      })
    }

    if (!hasError){
      LogUserIn(e)
    } 
  }

  return (
    <div {...cssLoginFormContainer}>
      <div {...cssLoginFormHeader}>SIGN IN</div>

      <div {...(hasError ? cssErrorText : cssErrorText_hide)}>
        {errorText}
      </div>
      ...
      // the form.
Shh
  • 299
  • 1
  • 6
  • 20
  • What is there is more than one error? – Shh Mar 21 '18 at 12:38
  • Not sure what the problem is at a glance, but it might help to take the extra "hasError" variable out, and instead check if `errorText === ""` – kingdaro Mar 21 '18 at 12:40

3 Answers3

1

I would take a different approach here for displaying errors, i.e. would implement error messages as separate values on your state:

this.state = {
   ...,
   errorEmail: '',
   errorPassword: ''
}

Set the state (for specific error you have):

this.setState({ 
    hasError: true,
    errorEmail: "\n - Email address is invalid. "
  })

And your errorText can be extracted in separate function to return your errors' text:

function errorText() {
   return `Errors: ${this.state.errorEmail} ${this.state.errorPassword}`
}

Note: you could also nest your errors under single errors object like so:

this.state = {
   ...,
   errors = { email: '', password: '' }
}

In this case, watch out for the state update (since it is nested). More info: How to update a nested state in React

Kox
  • 834
  • 7
  • 12
1

You have two problems here: first you're mutating the state using += to concatenate the strings. You probably want to use only +. State should only be changed using setState. When you do errorText = erroText+="whatever" you're changing the string in place. Try the following code on your console:

x = "hello"
y = x+=" world"
x
y

You'll see you changed x while trying to set y to a new value

if you do

x = "hello"
y = x+ " world"
x
y

You'll see only y changes

Second, you're using setState multiple times in a single function, which can lead to race conditions

You should try setting state only once at the end, keep the string and the boolean in variables and use them to set the state

1
  • Render function should not include any side-effect, so it's better to wrtie onTapLogin function outside render function.
  • I don't see the point of setState multiple times, since setState may trigger React lifecycle and it will NOT execute immediately (It's an async function).

I rearranged your code to fix the issues, but the code you got didn't call onTapLogin function, so you might need change it to fit your actually code:

class LoginForm extends Component {
  constructor(props) {
    super(props);
    this.state = {
      details: {
        email: '',
        password: '',
      },
      hasError: false,
      errorText: null,
    };
  }

  onTapLogin = e => {
    let errorText = 'Errors: \n';
    let hasError = false;

    if (!check.emailValid(e.email)) {
      errorText += 'Email address is invalid.\n';
      hasError = true;
    }
    if (!check.passwordValid(e.password)) {
      errorText += 'Password is invalid.\n';
      hasError = true;
    }

    if (!hasError) {
      this.logUserIn(e);
    } else {
      this.setState({
        errorText,
        hasError,
      });
    }
  };

  logUserIn = e => {}

  render() {
    const { hasError, errorText } = this.state;
    const { LogUserIn } = this.props;

    return <div>{hasError && <p>{errorText}</p>}</div>;
  }
}
FisNaN
  • 2,517
  • 2
  • 24
  • 39