puru
puru

Reputation: 150

How to return component in form Reactjs?

How can we create a stepper that is the multi-step form in Reactjs for multiple-step form submission? Currently, I am not showing component for each step

For now, I am able to return the component but it returns all the component at the same time, as I want to return component in the center for each step it passes.

Codesandbox link

Here is code for stepper which works perfectly

import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";
import "./Stepper.scss";

const Stepper = ({ stepColor, steps, direction, currentStep }) => {
  const [stepState, setStepState] = useState([]);

  useEffect(() => {
    let createSteps = steps.map((step, idx) => ({
      description: step.label,
      component: step.component,
      completed: idx < currentStep - 1, // past are completed
      selected: idx <= currentStep - 1, // past & present are colored
      highlighted: idx === currentStep - 1 // only present is highlighted
    }));

    setStepState(createSteps);
  }, [steps, currentStep]);

  return (
    <div className={`stepper-wrapper-${direction}`}>
      {stepState.map(
        ({ selected, completed, highlighted, description, component }, idx) => (
          <div className="step-wrapper" key={idx}>
            <div
              className={`step-number step-number-${
                selected ? "active" : "disabled"
              }`}
              style={{ background: `${selected ? stepColor : "none"}` }}
            >
              {completed ? "✔" : idx + 1}
            </div>
            <div
              className={`step-description ${
                highlighted ? "step-description-active" : ""
              }`}
            >
              {description}
            </div>
            {idx + 1 !== stepState.length && (
              <div
                className={`divider-line divider-line-${stepState.length}`}
              />
            )}
            <div>{component}</div>
          </div>
        )
      )}
    </div>
  );
};

Stepper.propTypes = {
  direction: PropTypes.string.isRequired,
  steps: PropTypes.array.isRequired
};

export default Stepper;

Image how it should look alike enter image description here

Upvotes: 0

Views: 120

Answers (1)

Tarukami
Tarukami

Reputation: 1160

You have an array of steps and you render forms within map method. That means the code is being rendered for every element of an array. And thats why you have received as many forms as you have elements in array of steps. If you want to hide or to show them you should render only the form of active (or highlited) step. In other words, this part of code should be rendered only if it is about current step.

<div
  className={`step-description ${
    highlighted ? "step-description-active" : ""
  }`}
>
  {description}
</div>
{idx + 1 !== stepState.length && (
  <div
    className={`divider-line divider-line-${stepState.length}`}
  />
)}
<div>{component}</div>

You can find a state (ex. highlighted) describing the index of object containing data for active form and use it like

{highlighted && <div>{description}</div>

But let me be honest - I would change a lot in your code. Form is better to be a component itself and just take data from state without any tricks within render section.

UPDATE: You can replace the piece of code mentioned above with this:

{highlighted &&  <div
    className={`step-description ${
      highlighted ? "step-description-active" : ""
    }`}
  >
    {description}
  </div>}
  {idx + 1 !== stepState.length && (
    <div
      className={`divider-line divider-line-${stepState.length}`}
    />
  )}
{highlighted && <div>{component}</div>}

Upvotes: 1

Related Questions