Reputation: 85805
I am using reactjs 16.
I am making a wizard and I am trying to design it in away that I can reuse it anywhere on my site I need it.
Here is my code
export default class App extends Component {
constructor(props) {
super(props);
}
render() {
const steps = [ {name: 'Step 1', component: <Step1 /> },
{name: 'Step 2', component: <Step2 /> }];
return (
<React.Fragment>
<WizardComponent steps={steps}/>
</React.Fragment>
);
}
}
import React, { Component } from "react";
import ReactDOM from "react-dom";
import WizardStepCompoent from "./WizardStepCompoent";
export default class WizardComponent extends Component {
constructor(props) {
super();
this.state = {
currentStep: 1
};
}
next(e) {
// need to update the current step look
// const step = this.props.steps.find(x => x.name == "Step 1")
// step.changeToCompleted() ----> go form {name: "Step 1", component: <Step 1/>} to {name: "Step 1", component: <Step 1/>, isCompleted: true}
}
render() {
const props = this.props;
return (
<div>
<div className="steps">
{props.steps.map(step => {
return <WizardStepCompoent step={step} />;
})}
</div>
{props.steps.map(step => {
return step.component; // later on use current state to figure out which one to render ie if currentStep == 1 then only render the 1st component
})}
<button onClick={ (e) => this.next(e) }>Next</button>
</div>
);
}
}
export default class WizardStepCompoent extends Component {
render() {
const props = this.props;
const step = props.step;
var completed = "";
if(step.isCompleted)
{
completed = "step-item is-completed";
} else {
completed = "step-item";
}
return (
<div className={completed}>
<div className="step-marker">
<span className="icon">
<i className="fa fa-check" />
</span>
</div>
<div className="step-details">
<p className="step-title">{step.name}</p>
<p>This is the first step of the process.</p>
</div>
</div>
);
}
Upvotes: 1
Views: 3822
Reputation: 25862
To solve what you are doing you need to clone the element and pass the appropriate props to it. here is an example in a codepen to see it live
class App extends React.Component {
render() {
const steps = [ {id: 'first', name: 'Step 1', component: <Step1 /> },
{id: 'second', name: 'Step 2', component: <Step2 /> }];
return (
<div>
<WizardComponent steps={steps}/>
</div>
);
}
}
class WizardComponent extends React.Component {
constructor(props) {
super();
this.state = {
currentStep: 0,
completedSteps: {
'first': {completed: false},
'second': {completed: false}
}
};
}
next(e) {
const {currentStep} = this.state
const completedSteps = {...this.state.completedSteps}
const current = this.props.steps[currentStep]
completedSteps[current.id].completed = true
this.setState({currentStep: this.state.currentStep + 1, completedSteps})
}
render() {
const props = this.props;
const {currentStep, completedSteps} = this.state
return (
<div>
<div className="steps">
{props.steps.map(step => {
return <WizardStepCompoent step={step} />;
})}
</div>
{props.steps.map((step, i) => {
return React.cloneElement(step.component, completedSteps[step.id]); // later on use current state to figure out which one to render ie if currentStep == 1 then only render the 1st component
})}
<button onClick={ (e) => this.next(e) }>Next</button>
</div>
);
}
}
the meat of what is happening is at the clone and also when you press next. I added to your steps an id as a way to cross reference each step, then you lookup the current step by its id and set a completed to true. This is a fairly basic example so please bear with me on that.
Upvotes: 2