I have a problem rendering a component with react. I'm trying to code a wizard, however I get the following error when rendering Mstep1.
Element type is invalid: expected a string (for built-in components) or a hereclass/function (for composite components) but got: object. You herelikely forgot to export your component from the file it's defined in.
To better explain, here is some code:
-- wizard.js --
import React, { Component } from 'react';
import { Mstep1, Mstep2 } from './Steps'
import { states } from './States'
import { StateMachine } from './StateMachine.js';
class Wizard extends Component {
constructor(props) {
super(props);
this.state = {
currentState: states.MSTEP1,
formSaves: [],
}
this.saveForm =this.saveForm.bind(this);
this.nextStep = this.nextStep.bind(this);
this.backStep = this.backStep.bind(this);
this.stateMachine = new StateMachine();
}
saveForm(formSave) {
let formSaves = this.state.formSaves.concat();
formSaves.push(formSave);
this.setState({
formSaves: formSaves
});
}
nextStep(desiredState) {
let currentState = this.state.currentState;
let nextState = this.stateMachine.transitionTo(currentState, desiredState);
this.setState({
currentState: nextState
});
}
backStep(desiredState) {
let currentState = this.state.currentState;
this.setState({
currentState: this.stateMachine.transitionFrom(currentState, desiredState)
});
}
//Switch Case Methode um den CurrentStep zu bestimmen
currentStep() {
console.log(this.state.currentState);
// console.log(typeof this.state.currentState);
switch (this.state.currentState) {
case states.MSTEP1:
console.log(typeof states.MSTEP1);
return <Mstep1
saveForm={this.save}
back={this.backStep}
next={this.nextStep}
/>;
break;
case states.MSTEP2:
return(<Mstep2
/>);
default:
break;
}
}
render() {
return (
<div>
{this.currentStep()}
</div>
);
}
}
export default Wizard;
--Steps.js---
import React, { Component } from 'react';
import { states } from './States.js';
import TextArea from './Select';
import SingleInput from './SingleInput';
// import Select from './Select';
export class Mstep1 extends Component {
constructor(props) {
super(props);
this.state = {
modultitel: '',
startdate: '',
enddate: '',
modulkuerzel: '',
modulDescription: ''
};
//Bindings
this.handleModultitel = this.handleModultitel.bind(this);
this.handleStartdate = this.handleStartdate.bind(this);
this.handleEnddate = this.handleEnddate.bind(this);
this.handleModulkuerzel = this.handleModulkuerzel.bind(this);
this.handlemodulDescriptionChange = this.handlemodulDescriptionChange.bind(this);
this.validate = this.validate.bind(this);
}
handleModultitel(e) {
this.setState({ modultitel: e.target.value }, () => console.log('modultitel:', this.state.modultitel));
}
handleStartdate(e) {
this.setState({ startdate: e.target.value }, () => console.log('startdate:', this.state.startdate));
}
handleEnddate(e) {
this.setState({ enddate: e.target.value }, () => console.log('enddate:', this.state.enddate));
}
handleModulkuerzel(e) {
this.setState({ modulkuerzel: e.target.value }, () => console.log('modulkuerzel', this.state.modulkuerzel));
}
handlemodulDescriptionChange(e) {
// const textArray = e.target.value.split('').filter(x => x !== 'e');
// console.log('string split into array of letters',textArray);
// const filteredText = textArray.join('');
// this.setState({ modulDescription: filteredText }, () => console.log('modulDescription', this.state.modulDescription));
this.setState({ modulDescription: e.target.value }, () => console.log('modulDescription', this.state.modulDescription));
}
handleClearForm(e) {
e.preventDefault();
this.setState({
modultitel: '',
startdate: '',
enddate: '',
modulkuerzel: '',
modulDescription: ''
});
}
validate(e) {
e.preventDefault();
this.props.saveForm({
modultitel: '',
startdate: '',
enddate: '',
modulkuerzel: '',
modulDescription: '',
});
this.props.next(this.props.nextState);
this.handleClearForm(e);
}
render() {
return (
<form>
<h5>Modul anlegen (Schritt 1 von x)</h5>
<SingleInput
inputType={'text'}
title={'Modultitel: '}
name={'name'}
controlFunc={this.handleModultitel}
content={this.state.modultitel}
placeholder={'Modultitel'} />
<SingleInput
inputType={'text'}
title={'Gültig ab: '}
name={'Startdate'}
controlFunc={this.handleStartdate}
content={this.state.startdate}
placeholder={'Startdatum'} />
<SingleInput
inputType={'text'}
title={'Gültig bis: '}
name={'Enddate'}
controlFunc={this.handleEnddate}
content={this.state.enddate}
placeholder={'Enddatum'} />
<SingleInput
inputType={'text'}
title={'Modulkürzel'}
name={'Modulkürzel'}
controlFunc={this.handleModulkuerzel}
content={this.state.modulkuerzel}
placeholder={'Modulkützel'} />
<TextArea
title={'Kurzbeschreibung'}
rows={5}
name={'Kurzbeschreibung'}
resize={false}
content={this.state.modulDescription}
controlFunc={this.handlemodulDescriptionChange}
placeholder={'Kurzbeschreibung zu Modulen'} />
<button
onClick={this.validate}>Weiter</button>
<button
onClick={this.handleClearForm}>Clear form</button>
</form>
);
}
}// Ende Class Mstep1
export class Mstep2 extends Component {
constructor(props) {
super(props);
this.state = {
modulThema: '',
themaDescription: ''
};
this.handleFormSubmit = this.handleFormSubmit.bind(this);
this.handleThemaDescription = this.handleThemaDescription.bind(this);
this.back = this.back.bind(this);
}
handleModulthema(e) {
this.setState({ modulThema: e.target.value }, () => console.log('thema: ', this.state.modulThema));
}
handleThemaDescription(e) {
this.setState({ themaDescription: e.target.value }, () => console.log('tDescription', this.state.themaDescription))
}
back(e) {
e.preventDefault();
this.props.back(states.MSTEP1);
}
validate(e) {
e.preventDefault();
this.props.saveForm({
modulThema: '',
themaDescription: ''
});
this.props.next(this.props.nextState);
this.handleClearForm(e);
}
render() {
return (
<form>
<h5>Modul anlegen (Schritt 2 von x)</h5>
<SingleInput
inputType={'text'}
title={'Neues Thema'}
name={'modulname'}
controlFunc={this.handleModulThema}
content={this.modulThema}
placeholder={'Modulthema'} />
<TextArea
title={'Beschreibung (Inhalte des Thmas)'}
rows={5}
name={'Thema-Beschreibung'}
resize={10}
controlFunc={this.handleThemaDescription}
content={this.state.themaDescription}
placeholder={''} />
<button
onClick={this.validate}>Weiter</button>
<button
onClick={this.back}>zurück</button>
<button
onClick={this.handleClearForm}>Clear form</button>
</form>
);
}
}
I would recommend you to split Mstep1 and Mstep2 into two different files and then you can export default class Mstep1 for example and import with import Mstep1 from 'Steps/Mstep1'. It's a good practice in React that you stick to one component per file. Refer to this article as a good reference to organize your react applications.
You can do export const class Mstep1 and export const Mstep2. So that you can import it like you already have.
Related
I have 2 components:
Form
EmailForm (which extends Form)
I don't understand why my state "errors" is not updated whenI submit the form button?
When I check in the component react tool in chrome dev tools nothing happens.
Do you know what I didn't do correctly in the handleSubmit and validate function?
import React from 'react';
import Form from './form';
class EmailForm extends Form {
state = {
data: { email: '' },
errors: {}
};
render() {
return (
<div>
<p>
<i>Renseignez votre email pour être averti dès que l'application sera disponible :</i>
</p>
<form onSubmit={this.handleSubmit}>
{this.renderInput('email', 'Email')}
{this.renderButton('Envoyer')}
</form>
</div>
);
}
}
export default EmailForm;
import React, { Component } from 'react';
import { ButtonPrimary } from './buttonPrimary';
import { ButtonTransparent } from './buttonTransparent';
import Input from './input2';
interface IFormState {
data: any;
errors: any;
}
class Form extends React.PureComponent<{}, IFormState> {
state = {
data: {},
errors: {}
};
validate = (): any => {
return { email: 'Email is required' };
};
validateProperty = (input: any) => {
console.log('validated Property');
};
handleSubmit = (e: any) => {
e.preventDefault();
const errors: any = this.validate();
this.setState({ errors });
if (errors) return;
this.doSubmit();
};
doSubmit = () => {
console.log('Submitted');
};
handleChange = ({ currentTarget: input }: any) => {
const errors: any = { ...this.state.errors };
const errorMessage: any = this.validateProperty(input);
if (errorMessage) errors[input.name] = errorMessage;
else delete errors[input.name];
const data: any = { ...this.state.data };
data[input.name] = input.value;
this.setState({ data, errors });
};
renderButton(label: string) {
return <ButtonPrimary disabled={!this.validate()}>{label}</ButtonPrimary>;
}
renderInput(name: string, label: string, type = 'email') {
const { data, errors }: any = this.state;
return (
<Input
autoFocus
type={type}
name={name}
value={data[name]}
label={label}
onChange={this.handleChange}
error={errors[name]}
/>
);
}
}
export default Form;
I'm scratching my head bleeding on this one.
Tried:
Reservation.insert(this.state);
const res = // Setting every field manually
const res = // Setting every field manually aswell as setting the parkingLot fields, as you can see in the code
I have not idea what else I could try, res.parkingLot always stays as an empty object. Which results in errors when trying to insert.
The full function is here:
handleSubmit(event, $) {
event.preventDefault();
const res = {
date: new Date(),
parkingLot: {
_id: this.state.parkingLot._id,
number: this.state.parkingLot.number,
name: this.state.parkingLot.name,
description: this.state.parkingLot.description,
price: this.state.parkingLot.price,
reserved: this.state.parkingLot.reserved,
},
user: $.state.user,
begin: $.state.begin,
end: $.state.end,
};
console.log('Submit', res, this.state);
Reservation.insert(res);
}
I was asked to add my whole Code so:
ReservationForm.js
import React, {Component} from 'react';
import {Reservation} from "../../../shared/collections/Reservation";
import {withTracker} from "meteor/react-meteor-data";
import {ParkingLot} from "../../../shared/collections/ParkingLot";
import MaterialSelect from "../form/MaterialSelect";
import * as M from "materialize-css";
class ReservationForm extends Component {
constructor(props) {
super(props);
this.state = {};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleBeginPicker = this.handleBeginPicker.bind(this);
this.handleEndPicker = this.handleEndPicker.bind(this);
}
componentDidMount() {
let beginPicker = document.querySelector('#begin');
let endPicker = document.querySelector('#end');
M.Datepicker.init(beginPicker, {
autoClose: true,
onSelect: this.handleBeginPicker
});
M.Datepicker.init(endPicker, {
autoClose: true,
onSelect: this.handleEndPicker
});
}
handleBeginPicker(date) {
const event = {
target: {
name: 'begin',
value: date
}
};
this.handleInputChange(event);
}
handleEndPicker(date) {
const event = {
target: {
name: 'end',
value: date
}
};
this.handleInputChange(event);
}
handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
handleSubmit(event) {
event.preventDefault();
try {
Reservation.insert(this.state, function(error) { error ? console.log( 'Insert Error', error) : null});
} catch (e) {
console.error(e);
M.toast({
html: e.reason,
});
}
}
render() {
const $ = this;
return (
<div className="row">
<h5>Reservierung anlegen</h5>
<form className="col s6" onSubmit={this.handleSubmit}>
<div className="row">
<label htmlFor='parkingLot'>Parkplatz</label>
<MaterialSelect ided='parkingLot'
named='parkingLot'
labeled='Parkplatz'
textField='name'
valueField='_id'
options={this.props.lots}
placeholder='Parkplatz wählen'
onChange={this.handleInputChange}/>
</div>
<div className="row input-field">
<input id='begin' name='begin' type='text' className='datepicker'
data-value={this.state.begin}/>
<label className='' htmlFor='begin'>Anfang</label>
</div>
<div className="row input-field">
<input id='end' name='end' type='text' className='datepicker'
data-value={this.state.end}/>
<label className='' htmlFor='end'>Ende</label>
</div>
<button className="btn waves-effect waves-light" type="submit" name="action"><i
className="material-icons right">create</i>Anlegen
</button>
</form>
</div>
);
}
}
export default withTracker(() => {
Meteor.subscribe('parkingLots');
return {
lots: ParkingLot.find({}).fetch(),
};
})(ReservationForm);
MaterialSelect.js
import React, {Component} from "react";
import {Random} from "meteor/random";
import * as M from "materialize-css";
export default class MaterialSelect extends Component {
constructor(props) {
super(props);
this.state = {value: this.props.value};
}
componentDidMount() {
let select = document.querySelector(`#${this.props.ided}`);
//M.FormSelect.init(select, {});
}
handleInputChange(event, $) {
event.preventDefault();
$.props.onChange(event);
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
render() {
const options = this.props.options.map(option => {
return <option value={!!this.props.valueField ? option[this.props.valueField] : option}
key={Random.id(4)}>{!!this.props.textField ? option[this.props.textField] : option}</option>
});
const $ = this;
return (
<select id={this.props.ided}
name={this.props.named}
defaultValue=''
value={this.state.value}
className='no-autoinit browser-default'
onChange={function(event) {$.handleInputChange(event, $)}} >
<option value="" disabled>{this.props.placeholder}</option>
<option value="crap value">Not Existing Value Test</option>
{options}
</select>
);
}
}
I tried this:
<script>
const res = {
date: new Date(),
parkingLot: {
_id: 11,
number: 12,
name: 'jhon',
description: 'j',
price: 3232,
reserved: true,
},
user: 'j',
begin: 'j',
end: 'j',
};
console.log(res);
</script>
and it works perfectly.
Are you sure all the properties are actually there? try to debug it in the console.
Does "this.state.parkingLot._id" actually returns a number?
Did you bind this in the component constructor?
class MyComponent extends React.Component {
constructor(props) {
super(props)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleSubmit(evt) {
...
}
}
As an alternative, you can use class properties and declare your event handlers as arrow functions instead. For that you would need the babel plugin #babel/plugin-proposal-class-properties
Also take a look at: https://reactjs.org/docs/faq-functions.html
Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op.
This is a react application, where a banner is fixed on the screen and passing random images. The way it was written is generating the warning in question.
import React from "react";
import Lightbox from "react-image-lightbox";
import logo from "./logo.png";
class Banner extends React.Component {
constructor(props) {
super(props);
this.state = {
images: [],
currentImage: logo,
isOpen: false,
sidebarOpen: true
};
}
async componentWillMount() {
await this.getBanners();
this.setState({ currentImage: this.state.images[0].url });
setInterval(async () => {
await this.getBanners();
}, 300000);
let i = 0;
setInterval(
() => {
this.setState({ currentImage: this.state.images[i].url });
if (i >= this.state.images.length - 1) {
i = 0;
} else {
i++;
}
},
10000,
i
);
}
async getBanners() {
const data = await (await fetch("/api/banners/active")).json();
if (data.true) {
this.setState({ images: data.true });
}
}
render() {
const { isOpen } = this.state;
return (
<div>
{isOpen && (
<Lightbox
mainSrc={this.state.currentImage}
onCloseRequest={() => this.setState({ isOpen: false })}
/>
)}
<footer>
<a>
<img
width={270}
height="200"
src={this.state.currentImage}
onClick={() => this.setState({ isOpen: true })}
alt="idk"
/>
</a>
</footer>
</div>
);
}
}
export default Banner;
Could anyone help improve this code?
You can put the numbers returned from setInterval on your instance and stop the intervals with clearInterval in componentWillUnmount so that they won't continue to run after the component has been unmounted.
class Banner extends React.Component {
constructor(props) {
super(props);
this.bannerInterval = null;
this.currentImageInterval = null;
this.state = {
images: [],
currentImage: logo,
isOpen: false,
sidebarOpen: true
};
}
async componentDidMount() {
await this.getBanners();
this.setState({ currentImage: this.state.images[0].url });
this.bannerInterval = setInterval(async () => {
await this.getBanners();
}, 300000);
let i = 0;
this.currentImageInterval = setInterval(
() => {
this.setState({ currentImage: this.state.images[i].url });
if (i >= this.state.images.length - 1) {
i = 0;
} else {
i++;
}
},
10000,
i
);
}
componentWillUnmount() {
clearInterval(this.bannerInterval);
clearInterval(this.currentImageInterval);
}
// ...
}
Use this template for any class-based component that has a state:
forgot about setState(), and use setComponentState declared down:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
// other fields...
isUnmounted: false,
};
}
componentWillUnmount() {
this.setState({ isUnmounted: true });
}
setComponentState = (values) => {
if (!this.state.isUnmounted) this.setState(values);
};
}
I have the following Higher Order Component to create a loading on my components:
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import Spinner from 'components/spinner';
const WithSpinner = (WrappedComponent) => {
return class SpinnerWrapper extends Component {
componentWillReceiveProps(nextProps) {
console.log('Current props: ', this.props);
console.log('Next props: ', nextProps);
}
render (){
const { loading } = this.props;
return (
<div>
{loading ?
<Spinner />
:
<WrappedComponent {...this.props}>{this.props.children}</WrappedComponent>}
</div>)
}
}
SpinnerWrapper.propTypes = {
loading: PropTypes.bool,
};
SpinnerWrapper.defaultProps = {
loading: true,
};
return SpinnerWrapper;
};
export default WithSpinner;
and I have the following component who is wrapping in WithSpinner
const updateChartSeries = answersSummary => ({
chartSeries: TasksTransforms.fromAnswerSummaryToClickEffectivenessChart(answersSummary),
transposed: false,
viewOptions: { type: 'pie', stacked: false, column: false },
});
class ClickEffectivenessChart extends Component {
constructor(props) {
super(props);
this.state = {
chartSeries: [],
viewOptions: {
type: 'pie',
stacked: false,
column: false,
},
title: 'Click Effectiveness',
};
}
componentWillReceiveProps({ answersSummary }) {
this.setState(updateChartSeries(answersSummary));
}
handleChartType = (type = 'pie') => {
switch (type) {
case 'pie':
this.setState({ viewOptions: { type: 'pie', stacked: false, column: false } });
break;
case 'bar':
this.setState({ viewOptions: { type: 'bar', stacked: false, column: false } });
break;
case 'column':
this.setState({ viewOptions: { type: 'bar', stacked: false, column: true } });
break;
default:
break;
}
}
optionsDropdown = () => {
const options = [
{ onClick: () => this.handleChartType('pie'), text: 'Pie' },
{ onClick: () => this.handleChartType('bar'), text: 'Bar' },
{ onClick: () => this.handleChartType('column'), text: 'Column' },
];
return options;
}
render() {
const { chartSeries, viewOptions, title } = this.state;
return (
chartSeries.length > 0 &&
<div className="content" >
<h4>{title}</h4>
<div className="box">
<EffectivenessChart type={viewOptions.type} series={chartSeries} title={title} optionMenu={this.optionsDropdown()} stacked={viewOptions.stacked} column={viewOptions.column} transposed />
</div>
</div>
);
}
}
ClickEffectivenessChart.propTypes = {
answersSummary: PropTypes.object, //eslint-disable-line
};
ClickEffectivenessChart.defaultProps = {
answersSummary: {},
};
export default WithSpinner(ClickEffectivenessChart);
And sometimes the componentWillReceiveProps it no trigger and I can see why. I'm assuming that my WithSpinner controller have a problem but I can see what is the problem. The same behavior happen in all components wrapped with the WithSpinner controller
Any help please?
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Heatmap from 'components/heatmap';
import ClickEffectivenessChart from './click_effectiveness_chart';
import ClickEffectivenessTable from './click_effectiveness_table';
import AreaChart from './area_chart';
import SctHeatmap from './sct_heatmap';
class SctAnswersSummary extends Component {
componentDidMount() {
if (this.props.questionId) { this.fetchData(); }
}
componentDidUpdate(prevProps) {
if (prevProps.questionId !== this.props.questionId) { this.fetchData(); }
}
fetchData = () => {
const {
datacenterId, accountId, projectId, questionId,
} = this.props;
this.props.actions.questionFetchRequest(datacenterId, accountId, projectId, questionId);
this.props.actions.answersSummaryFetchRequest(datacenterId, accountId, projectId, questionId);
this.props.actions.answersSctClicksFetchRequest(datacenterId, accountId, projectId, questionId);
}
render() {
const { imageUrl, clicks, questionId, imageWidth, imageHeight } = this.props.answerSctClicks;
const { answersSummaryLoading, answersSctLoading, answersSummary } = this.props;
return (
<div className="content">
<div className="content" >
<SctHeatmap imageUrl={imageUrl} clicks={clicks} questionId={questionId} imageWidth={imageWidth} imageHeight={imageHeight} loading={answersSctLoading} />
<br />
<ClickEffectivenessChart answersSummary={answersSummary} loading={answersSummaryLoading} />
<br />
<AreaChart answersSummary={answersSummary} loading={answersSummaryLoading} />
<br />
<ClickEffectivenessTable answersSummary={answersSummary} loading={answersSummaryLoading} />
</div>
</div>
);
}
}
SctAnswersSummary.propTypes = {
datacenterId: PropTypes.string,
accountId: PropTypes.string,
projectId: PropTypes.string,
questionId: PropTypes.string,
questionSct: PropTypes.object, // eslint-disable-line react/forbid-prop-types
actions: PropTypes.shape({
questionSctFetchRequest: PropTypes.func,
}).isRequired,
answersSummaryLoading: PropTypes.bool,
answersSctLoading: PropTypes.bool,
};
SctAnswersSummary.defaultProps = {
datacenterId: null,
accountId: null,
projectId: null,
questionId: null,
questionSct: {},
answersSummaryLoading: true,
answersSctLoading: true,
};
export default SctAnswersSummary;
It's because your HOC is a function stateless component, meaning that it doesn't have any lifecycle events. You need to convert WithSpinner to a class component and then the lifecycle events should flow through to your wrapped component:
const WithSpinner = (WrappedComponent) => {
return class extends React.Component {
componentWillReceiveProps(nextProps) {
console.log('Current props: ', this.props);
console.log('Next props: ', nextProps);
}
render() {
return <div>
{this.props.loading ?
<Spinner />
:
<WrappedComponent {...this.props}>
{this.props.children}
</WrappedComponent>}
</div>
}
}
}
How do I send the stats from FMoStep1.js to the wizard in the formSaves array? I tried to pass the stats to the wizard with the method handleFormSubmit but it does not work.
Then, there is also a problem with step changing, it does not change from FMoStep1 to FMoStep2.
Wizard.js
import React, { Component } from 'react';
import FMoStep1 from './FMoStep1';
import FMoStep2 from './FMoStep2';
import FMoStep3 from './FMoStep3';
import { states } from './States'
import { StateMachine } from './StateMachine.js';
class Wizard extends Component {
constructor(props) {
super(props);
this.state = {
currentState: states.FMoStep1,
formSaves: []
}
this.saveForm = this.saveForm.bind(this);
this.nextStep = this.nextStep.bind(this);
this.backStep = this.backStep.bind(this);
this.stateMachine = new StateMachine();
}
nextStep(desiredState) {
let currentState = this.state.currentState;
let nextState = this.stateMachine.transitionTo(currentState, desiredState);
this.setState({
currentState: nextState
});
}
backStep(desiredState) {
let currentState = this.state.currentState;
this.setState({
currentState: this.stateMachine.transitionFrom(currentState, desiredState)
});
}
saveForm(formSave) {
let formSaves = this.state.formSaves.concat();
formSaves.push(formSave);
this.setState({
formSaves: formSaves
});
}
//Switch Case Methode um den CurrentStep zu bestimmen
currentStep() {
switch (this.state.currentState) {
case states.FMoStep1:
return (
<FMoStep1
saveForm={this.saveForm}
back={this.backStep}
next={this.nextStep} />
);
case states.FMoStep2:
return (
<FMoStep2
saveForm={this.saveForm}
back={this.backStep}
next={this.nextStep} />
);
case states.FMoStep3:
return (
<FMoStep3
saveForm={this.saveForm}
back={this.backStep}
next={this.nextStep} />
);
default:
break;
}
}
render() {
return (
<div>{ this.currentStep() }</div>
);
}
}
export default Wizard;
FMoStep1
import React, { Component } from 'react';
import SingleInput from './SingleInput';
import TextArea from './TextArea';
class FMoStep1 extends Component {
constructor(props) {
super(props);
this.state = {
modultitel: '',
startdate: '',
enddate: '',
modulkuerzel: '',
modulDescription: ''
};
this.handleModultitel = this.handleModultitel.bind(this);
this.handleStartdate = this.handleStartdate.bind(this);
this.handleEnddate = this.handleEnddate.bind(this);
this.handleModulkuerzel = this.handleModulkuerzel.bind(this);
this.handlemodulDescriptionChange = this.handlemodulDescriptionChange.bind(this);
this.handleClearForm = this.handleClearForm.bind(this);
this.handleFormSubmit = this.handleFormSubmit.bind(this);
}
handleModultitel(e) {
this.setState(
{ modultitel: e.target.value },
() => console.log('modultitel:', this.state.modultitel)
);
}
handleStartdate(e) {
this.setState(
{ startdate: e.target.value },
() => console.log('startdate:', this.state.startdate)
);
}
handleEnddate(e) {
this.setState(
{ enddate: e.target.value },
() => console.log('enddate:', this.state.enddate)
);
}
handleModulkuerzel(e) {
this.setState(
{ modulkuerzel: e.target.value },
() => console.log('modulkuerzel', this.state.modulkuerzel)
);
}
handlemodulDescriptionChange(e) {
this.setState(
{ modulDescription: e.target.value },
() => console.log('modulDescription', this.state.modulDescription)
);
}
handleClearForm(e) {
e.preventDefault();
this.setState({
modultitel: '',
startdate: '',
enddate: '',
modulkuerzel: '',
modulDescription: ''
});
}
handleFormSubmit(e) {
e.preventDefault();
const formPayload = {
modultitel: this.state.modultitel,
startdate: this.state.startdate,
enddate: this.state.enddate,
modulkuerzel: this.state.modulkuerzel,
modulDescription: this.state.modulDescription
};
console.log('send befor', formPayload)
this.props.next(this.props.nextState);
console.log('Send this in a Post request:', this.state);
//States übertragen in die Session
this.props.saveForm(formPayload);
this.handleClearForm(e);
}
render() {
return (
<form>
<h5>Modul anlegen (Schritt 1 von x)</h5>
<SingleInput
inputType={'text'}
title={'Modultitel: '}
name={'name'}
controlFunc={this.handleModultitel}
content={this.state.modultitel}
placeholder={'Modultitel'} />
<SingleInput
inputType={'text'}
title={'Gültig ab: '}
name={'Startdate'}
controlFunc={this.handleStartdate}
content={this.state.startdate}
placeholder={'Startdatum'} />
<SingleInput
inputType={'text'}
title={'Gültig bis: '}
name={'Enddate'}
controlFunc={this.handleEnddate}
content={this.state.enddate}
placeholder={'Enddatum'} />
<SingleInput
inputType={'text'}
title={'Modulkürzel'}
name={'Modulkürzel'}
controlFunc={this.handleModulkuerzel}
content={this.state.modulkuerzel}
placeholder={'Modulkützel'} />
<TextArea
title={'Kurzbeschreibung'}
rows={5}
name={'Kurzbeschreibung'}
resize={false}
content={this.state.modulDescription}
controlFunc={this.handlemodulDescriptionChange}
placeholder={'Kurzbeschreibung zu Modulen'} />
<button
onClick={this.handleFormSubmit}>Weiter</button>
<button
onClick={this.handleClearForm}>Clear form</button>
</form>
);
}
}
export default FMoStep1;
Thank you!
You are relying on the nextState prop to navigate to the nextState in the the FMoStep1 component which you aren't supplying. Pass then and it should work
switch (this.state.currentState) {
case states.FMoStep1:
return <FMoStep1
saveForm={this.saveForm}
nextState={states.FMoStep2}
back={this.backStep}
next={this.nextStep}
/>;
case states.FMoStep2:
return (<FMoStep2
saveForm={this.saveForm}
nextState={states.FMoStep3}
back={this.backStep}
next={this.nextStep}
/>);
case states.FMoStep3:
return (<FMoStep3
saveForm={this.saveForm}
back={this.backStep}
next={this.nextStep}
/>);
default:
break;
}
P.S. However I would suggest you to restructure your code and maybe use routes instead of conditional rendering of the components