Comment rendre active l'étape visitée?

Sep 11 2020

Je crée une application de réaction simple et une bibliothèque horizontale react-stepper-horizontale incluse et tout va bien.

Exemple de travail:

Code approprié lié au stepper:

const Form = () => {
.
.
.

const [currentPage, setCurrentPage] = useState(1);
const sections = [
  { title: 'Basic Details', onClick: () => setCurrentPage(1) },
  { title: 'Employment Details', onClick: () => setCurrentPage(2) },
  { title: 'Review', onClick: () => setCurrentPage(3) },
];
    
<Stepper
  steps={sections}
  activeStep={currentPage}
  activeColor="red"
  defaultBarColor="red"
  completeColor="green"
  completeBarColor="green"
/>

.
.
.
}

Étapes pour reproduire le problème:

-> Il y a au total trois étapes 1,2,3et chacune a des sections différentes comme Basic Details, Employment Detailset Reviewrespectivement.

-> Maintenant, si l'utilisateur saisit l'un des champs de saisie à l'étape 1 et passe à l'étape 2, remplit certains champs de saisie et passe à l'étape 3 pour le revoir et s'il revient à nouveau à l'étape 1, l'état actif est perdu dans Étape 3.

-> Alors maintenant, le problème est que si nous voulons passer à l'étape 3, nous devons à nouveau faire trois étapes pour atteindre la dernière étape 3.

Exigence:

-> Si l'utilisateur a déjà visité une étape, s'il en vient à une étape précédente, toutes les étapes qu'il a visitées précédemment doivent être actives.

Par exemple:

-> Si l'utilisateur a atterri Step 1, puis en utilisant le bouton suivant, il atteint le Step 3et s'il souhaite revenir pour Step 1modifier certaines entrées et à nouveau s'il veut passer à l' Step 3étape de révision, cela devrait être possible en cliquant sur le Step 3car il déjà visité cette étape.

Veuillez m'aider à obtenir le résultat de rendre les étapes à l'état actif jusqu'à ce que l'utilisateur visite. Si l'utilisateur visite l'étape 3 et retourne à l'étape 1 en cliquant sur le cercle Étape 1, il devrait être possible de revenir à l'étape 3 encore une fois comme il a déjà visité l'étape 3 ..

Toute solution sans aucune bibliothèque est également la bienvenue.

C'est un gros problème si nous avons plus d'étapes (par exemple 7 étapes). Alors merci de bien vouloir m'aider .. Un grand merci à l'avance ..

Réponses

hackape Sep 30 2020 at 15:30

Voici une implémentation simple du <Stepper />composant en question. La clé est d'avoir un trackerqui suit les étapes visitées en interne, persiste ces informations à travers les re-rendus.

Aire de jeu Demoboard

const { useState, useEffect, useMemo } = React;
const cx = classNames;

function range(a, b) {
  return new Array(Math.abs(a - b) + 1).fill(a).map((v, i) => v + i);
}

function Stepper({ steps, activeStep, children }) {
  const count = steps.length;
  const listOfNum = useMemo(() => range(1, count), [count]);
  const tracker = useMemo(() => {
    let highestStep = 0;

    function hasVisited(step) {
      return highestStep >= step;
    }

    function addToBackLog(step) {
      if (step > highestStep) highestStep = step;
    }

    return {
      hasVisited,
      addToBackLog,
      getHighestStep() {
        return highestStep;
      },
    };
  }, []);

  tracker.addToBackLog(activeStep);

  const noop = () => {};

  const prevStep = steps[activeStep - 2];
  const currentStep = steps[activeStep - 1];
  const nextStep = steps[activeStep];

  return (
    <div>
      <div>
        {" "}
        {listOfNum.map((num, i) => {
          const isActive = activeStep == num;
          const isVisited = tracker.hasVisited(num);
          const isClickable = num <= tracker.getHighestStep() + 1 || isVisited;
          return (
            <div
              key={num}
              className={cx("circle", {
                active: isActive,
                visited: isVisited,
                clickable: isClickable,
              })}
              onClick={isClickable ? steps[i].onClick : noop}
            >
              {num}{" "}
            </div>
          );
        })}{" "}
      </div>{" "}
      <h2> {currentStep && currentStep.title} </h2> <div> {children} </div>{" "}
      <div className="footer">
        {" "}
        {prevStep ? (
          <button onClick={prevStep.onClick}> prev </button>
        ) : null}{" "}
        {nextStep ? <button onClick={nextStep.onClick}> next </button> : null}{" "}
      </div>{" "}
    </div>
  );
}

function App() {
  const [currentPage, setCurrentPage] = useState(1);
  const sections = [
    {
      title: "Un",
      onClick: () => setCurrentPage(1),
    },
    {
      title: "Deux",
      onClick: () => setCurrentPage(2),
    },
    {
      title: "Trois",
      onClick: () => setCurrentPage(3),
    },
    {
      title: "Quatre",
      onClick: () => setCurrentPage(4),
    },
    {
      title: "Cinq",
      onClick: () => setCurrentPage(5),
    },
  ];

  return (
    <Stepper steps={sections} activeStep={currentPage}>
      I 'm page {currentPage}{" "}
    </Stepper>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));
body {
  color: #0f0035;
  padding-bottom: 2rem;
}

.circle {
  display: inline-flex;
  height: 2em;
  width: 2em;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background-color: lightgrey;
  margin: 0 0.5em;
  color: white;
  cursor: not-allowed;
}

.active {
  background-color: rgba(50, 50, 250) !important;
}

.visited {
  background-color: rgba(50, 50, 250, 0.5);
}

.clickable {
  cursor: pointer;
}

.footer {
  margin-top: 1em;
  display: flex;
  justify-content: space-between;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/classnames/2.2.6/index.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>