Loading indicator inside the reduction mold
I am trying to display a loading indicator inside a redux form and I want the loading indicator to fit inside the content of the map (Bulma CSS structure). The code below works because of the conditional validation logic in the render function. When ticket
null
, I'll be right back <div>Loading</div>
. But when I remove this condition, it can display the loading progress bar, but the form cannot display the initial values, although it consists of the initial values ββin props redux-form
. Anyone have a scenario like this before and how to solve it correctly?
import React, { Component } from 'react';
import TicketForm from '../TicketForm/TicketForm';
import CustomerForm from '../CustomerForm/CustomerForm';
class TicketPanel extends Component {
componentWillMount() {
this.props.fetchTicket(this.props.ticketId);
}
render() {
const {ticket, loading, error} = this.props.activeTicket;
const isComponentLoading = loading || ticket === null;
const initialValuesForTicket = isComponentLoading ? {} : ticket.original_ticket_payload;
const initialValuesForCustomer = isComponentLoading ? {} : ticket.contact;
if (error) {
return <div>Error</div>
} else if (ticket === null) {
return <div>Loading</div>
}
return (
<div className="ticket-panel">
<TicketForm
loading={isComponentLoading}
initialValues={initialValuesForTicket} />
</div>
)
}
}
export default TicketPanel;
Below is the component code, which consists of the logic that displays the form. It will show the form component or load component, depends on the loading
props value that is passed from the parent.
import React, { Component } from 'react';
import CSSModules from 'react-css-modules';
import {Field, reduxForm} from 'redux-form';
import {ID_TYPE_COLLECTION} from 'utilities/constant';
import styles from './TicketForm.scss';
class TicketForm extends Component {
renderIdTypes () {
return ID_TYPE_COLLECTION.map(idType => {
return <option key={idType.value} value={idType.value}>{idType.title}</option>;
});
}
render() {
const {handleSubmit, loading} = this.props;
const loadingComponentClass = loading ? "card-content" : "is-hidden";
const formComponentClass = loading ? "is-hidden" : "card-content";
return (
<div className="card">
<header className="card-header">
<p className="card-header-title">
Ticket
</p>
</header>
<form onSubmit={handleSubmit}>
<div className={loadingComponentClass}>
<div className="content">
<div className="is-component-loading"></div>
</div>
</div>
<div className={formComponentClass}>
<div className="content">
<div className="field is-horizontal">
<div className="field-label">
<label className="label">
Name
</label>
</div>
<div className="field-body">
<div className="field">
<div className="control">
<Field className="input" name="name" component="input" type="text" placeholder="Name" />
</div>
</div>
</div>
</div>
<div className="field is-horizontal">
<div className="field-label">
<label className="label">
ID Type
</label>
</div>
<div className="field-body">
<div className="field">
<div className="control">
<div className="select is-fullwidth">
<Field className="input" name="owner_id_type" component="select">
{this.renderIdTypes()}
</Field>
</div>
</div>
</div>
</div>
</div>
<div className="field is-horizontal">
<div className="field-label">
<label className="label">
NRIC
</label>
</div>
<div className="field-body">
<div className="field">
<div className="control">
<Field className="input" name="nric" component="input" type="text" placeholder="NRIC" />
</div>
</div>
</div>
</div>
<div className="field is-horizontal">
<div className="field-label">
<label className="label">
Car Plate
</label>
</div>
<div className="field-body">
<div className="field">
<div className="control">
<Field className="input" name="car_plate" component="input" type="text" placeholder="Car Plate" />
</div>
</div>
</div>
</div>
<div className="field is-horizontal">
<div className="field-label">
<label className="label">
Mileage
</label>
</div>
<div className="field-body">
<div className="field">
<div className="control">
<Field className="input" name="mileage" component="input" type="text" placeholder="Mileage" />
</div>
</div>
</div>
</div>
</div>
</div>
<footer className="card-footer">
<a className="card-footer-item">Reset</a>
<a className="card-footer-item">Save</a>
</footer>
</form>
</div>
);
}
}
TicketForm = reduxForm({
form: 'TicketForm' // a unique identifier for this form
})(TicketForm)
export default CSSModules(TicketForm, styles)
source to share
I found an approach to solve my problem. Basically I just transfer my form to another functional component like the code below. My original component will display a loading indicator, which is a renderLoading
function and Form
depends on props that are passed from the parent.
import React, { Component } from 'react';
import CSSModules from 'react-css-modules';
import {Field, reduxForm} from 'redux-form';
import {ID_TYPE_COLLECTION} from 'utilities/constant';
import styles from './TicketForm.scss';
let Form = ({handleSubmit}) => {
const renderIdTypes = () => {
return ID_TYPE_COLLECTION.map(idType => {
return <option key={idType.value} value={idType.value}>{idType.title}</option>;
});
}
return (
<form onSubmit={handleSubmit}>
<div className="card-content">
<div className="content">
<div className="field is-horizontal">
<div className="field-label">
<label className="label">
Name
</label>
</div>
<div className="field-body">
<div className="field">
<div className="control">
<Field className="input" name="name" component="input" type="text" placeholder="Name" />
</div>
</div>
</div>
</div>
<div className="field is-horizontal">
<div className="field-label">
<label className="label">
ID Type
</label>
</div>
<div className="field-body">
<div className="field">
<div className="control">
<div className="select is-fullwidth">
<Field className="input" name="owner_id_type" component="select">
{renderIdTypes()}
</Field>
</div>
</div>
</div>
</div>
</div>
<div className="field is-horizontal">
<div className="field-label">
<label className="label">
NRIC
</label>
</div>
<div className="field-body">
<div className="field">
<div className="control">
<Field className="input" name="nric" component="input" type="text" placeholder="NRIC" />
</div>
</div>
</div>
</div>
<div className="field is-horizontal">
<div className="field-label">
<label className="label">
Car Plate
</label>
</div>
<div className="field-body">
<div className="field">
<div className="control">
<Field className="input" name="car_plate" component="input" type="text" placeholder="Car Plate" />
</div>
</div>
</div>
</div>
<div className="field is-horizontal">
<div className="field-label">
<label className="label">
Mileage
</label>
</div>
<div className="field-body">
<div className="field">
<div className="control">
<Field className="input" name="mileage" component="input" type="text" placeholder="Mileage" />
</div>
</div>
</div>
</div>
</div>
</div>
<footer className="card-footer">
<a className="card-footer-item">Reset</a>
<a className="card-footer-item">Save</a>
</footer>
</form>
);
}
Form = reduxForm({
form: 'TicketForm' // a unique identifier for this form
})(Form)
class TicketForm extends Component {
renderLoading() {
return (
<div>
<div className="card-content">
<div className="content">
<div className="is-component-loading"></div>
</div>
</div>
<footer className="card-footer">
<a className="card-footer-item">Reset</a>
<a className="card-footer-item">Save</a>
</footer>
</div>
)
}
render() {
const {loading, initialValues} = this.props;
const component = loading
? this.renderLoading()
: <Form initialValues={initialValues} />;
return (
<div className="card">
<header className="card-header">
<p className="card-header-title">
Ticket
</p>
</header>
{component}
</div>
);
}
}
export default CSSModules(TicketForm, styles)
source to share