2

My parent component, basically a form, has a child, an overlay with a loader, which only has to be displayed based on parent's state.

import React from 'react';
import Overlay from './overlay';

export default class RegisterForm extends React.Component {
  constructor {
    this.state = {
      loading: false
    };
  }
  handleSubmit(){
    this.state.loading = true;
    ...
  }

  render(){
    return(
    <form onSubmit={() => this.handleSubmit()}>
     ...
     <Overlay />
    </form>
    );
  }
}

How can I achieve this?

I tried React.cloneElement(<Overlay />, {}) but I don't know how to re-append this child to the parent and as I understand, it's not the React-way of doing things...

I also tried setting a prop ob Overlay based on state of the parent, like React.cloneElement(<Overlay />, { visible = this.state.loading }) but cannot seem to get it to work...

afkatja
  • 301
  • 4
  • 13

2 Answers2

5

I would prefer the expression below than a ternary operator for the case in question

render() {
  return (
    <form onSubmit={this.handleSubmit}>
      { this.state.loading == false && <Overlay /> }
    </form>
  );
}

Remember not to miss a return clause in the render function. Remember not to change state by assignment directly. Here is a working component that submits the form by clicking a button, and displays a loading message. This is a typical React way to achieve the behavior.

class HelloWidget extends React.Component{
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this)
    this.state = {
      loading: false
     };
  }
  handleSubmit() {
    this.setState({ loading: true });
  }
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        { this.state.loading && <div>loading...</div> }
        <button>click</button>
       </form>
     );
  }
}

Appendix - Below are two shorthand tricks.

Ternary operator:

Shorthand

render() {
  return condition === someCondition ? <CompA /> : <CompB />;
}

Longhand

render() {
  if ( condition === someCondition ) {
    return <CompA />;
  } else {
    return <CompB />;
  }
}

Boolean AND operator &&:

Shorthand

render() {
  return condition === someCondition && <CompA />;
}

Longhand

render() {
  if ( condition === someCondition ) {
    return <CompA />;
  } else {
    return null;
  }
}
Season
  • 4,056
  • 2
  • 16
  • 23
4

Make use of ternary operator to render you component. React JSX supports If-else logic for rendering like {(this.state.loading == false) ? <Overlay /> : null}

You should use this.setState({loading: true}); to change state instead of a direct assignment. Also use event.preventDefault() in your handleSubmit();

import React from 'react';
import Overlay from './overlay';

export default class RegisterForm extends React.Component {
  constructor {
    this.state = {
      loading: false
    };
  }
  handleSubmit(event){
   event.preventDefault();
    this.setState({loading: true});
    ...
  }

  render(){
    <form onSubmit {()=>{this.handleSubmit()}>

     {(this.state.loading == false) ? <Overlay /> : null}
    </form>
  }
}
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400