javascriptreactjsreact-state-managementreact-statereact-lifecycle-hooks

Loading component not rendering in React.js form component?


I want this loader to render while my fetch is making its request. I have a <Loader/> component which doesn't seem to render though? Isn't my logic and life-cycle usage correct?

I've added some comments throughout the form...

import React, { Component } from 'react'
import { Loader, Transition, Button, Form, Grid, Header, Message, Segment } from 'semantic-ui-react'
import Link from 'next/link';
import Router from 'next/router'
import { login } from 'next-authentication'

import { connect } from 'react-redux'


class LoginForm extends Component {
 constructor(props) {
  super(props)

  this.state = {
   isLoading: true, // other state has been omitted for brevity, but I set to true here...
  }

  this.handleChange = this.handleChange.bind(this)
  this.handleBlur = this.handleBlur.bind(this)
  this.handleSubmit = this.handleSubmit.bind(this)

 }

 componentDidMount() {
  this.setState({ isLoading: false }) // when my component mounts the first time, its set to false.
 }



 handleSubmit(event) {
  this.setState({
   isLoading: true // then I set it to true again when the submit is called
  })

  event.preventDefault();

  var error = false;

  var { username, password, isLoading } = this.state

  var mailFormat = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/


  if (!username.match(mailFormat)) {
   this.setState({ usernameError: true });
   error = true;
  } else {
   this.setState({ usernameError: false });
  }

  if (password.length < 8) {
   this.setState({ passwordError: true });
   error = true;
  } else {
   this.setState({ passwordError: false })
  }

  if (error) {
   this.setState({ formSuccess: false });
   return;
  }

  {console.log("isLoading 1", isLoading)}


  return window.fetch('http://localhost:8016/users/login', {
   method: 'POST',
   headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
   body: JSON.stringify({ username, password })
  })
   .then((response) => {
    if (response.ok) {

     const { token } = response.clone();

     const loginOptions = {
      token,
      cookieOptions: { expires: 1 },
      callback: () => Router.push('/profile')
     }
     setTimeout(() => {
      login(loginOptions)
     }, 5000)

     this.setState({
      username: username, password: '', formError: false, formSuccess: true, isLoading:false
     }) // set back to false because it should be finished as I've gotten my response

    } else if (!response.ok) {
     if (response.status === 404) {
      console.log("response.status ", response.status);
      {console.log("isLoading 2", isLoading)}
      this.setState({
        formError: true, formSuccess: false, isLoading:false // same here
      });
      return;
     }
    }
    return response;
   })
   .catch(err => console.dir(err))
 }

 render() {
  var { username, password, usernameError, passwordError, formSuccess, formError, duration, isLoading } = this.state;

  const { state} = this.props;


  // (formSuccess === true) ? state.isLoggedIn = true : state.isLoggedIn = false;

  return (<div className='login-form'> {

  }<style>{`body > div, body > div > div, body > div > div > div.login-form { height: 100%;}`} </style>

   <Grid textAlign='center'
    style={{ height: '100%' }}
    verticalAlign='middle' >
    <Grid.Column style={{ maxWidth: 450 }}>
     <Header as='h2'
      color='teal'
      textAlign='center'>
      Log-in to your account
     </Header>

     <Form size='large'
      onSubmit={this.handleSubmit}
      error={ formError}>


      <Segment stacked>
       <Form.Input fluid icon='user'
        iconPosition='left'
        placeholder='E-mail address, e.g. joe@schmoe.com'
        name='username'
        value={username}
        onBlur={this.handleBlur}
        onChange={this.handleChange}
        error={usernameError}
       />

       <Transition visible={usernameError}
        animation='scale'
        duration={duration}>
        <Message error content='username_Email is in incorrect format e.g. joe@schmoe.com' />
       </Transition>

       <Form.Input fluid icon='lock'
        iconPosition='left'
        placeholder='Password'
        name='password'
        value={password}
        onBlur={this.handleBlur}
        onChange={this.handleChange}
        error={passwordError}
       />

       <Transition visible={passwordError}
        animation='scale'
        duration={duration}>
        <Message error content='Password is incorrect, please try again.' />
       </Transition>

       <Button color='teal'
        fluid size='large'
        disabled={!username || !password}>
        Log-in
       </Button>

       {isLoading
        ? <Loader> Loading </Loader> //shouldn't it fire here?
        : <Transition visible={ formError}
         unmountOnHide={true}
         animation='scale'
         duration={duration}>
         <Message
          error
          centered="true" header='This email does not exist...'
          content='Please re-enter another email address, or  click the link below to register.' />
        </Transition>
       }

       {isLoading 
        ? <Loader> Loading </Loader> //shouldn't it fire here?
        : <Transition visible={formSuccess}
         unmountOnHide={true}
         animation='scale'
         duration={duration}>
         <Message
          success
          header='Your have successfully logged in.'
          content='Welcome to Hillfinder!' />
        </Transition>
       }
      </Segment>
     </Form>

     {formError ?
      <Transition visible={formError}
       animation='scale'
       duration={1000}>
       <Message>
        <Link href="/register">
         <a>Register</a>
        </Link> </Message>
      </Transition>
      : null
     }
    </Grid.Column> </Grid> </div>
  )
 }
}

const mapStateToProps = state => {
 return {
  state
 }
}

export default connect(mapStateToProps)(LoginForm)

Solution

  • You forgot to use the active props of the loader. It should be like:

    {isLoading
            ? <Loader active> Loading </Loader> //It'll be spinning now
           // ...
    }