user11631308
user11631308

Reputation:

React render multiple buttons in for loop from given integer

I am building a progress bar which takes two inputs, totalSteps and activeStep. I am going to render a number of circles equal to the number of total steps, with the active step being grey. enter image description here

I have experience mapping over an array of objects however in this case I don't have an array I am just given an integer.

I am attempting to write a function which returns a div in a for loop but this isn't working.

const ProgressBar = (props) => {
  const { activeStep, totalSteps } = props;

  const displayProgressBar = () => {
    for (let i = 1; i <= totalSteps; i++) {
      return <div>Hello</div>;
    }
  };
  return <div className="progressBar">{displayProgressBar()}</div>;
};

The above code only renders Hello once even if totalSteps is 3. Is there a way to achieve the desired results without creating an array?

Upvotes: 4

Views: 7275

Answers (4)

ibrahim mahrir
ibrahim mahrir

Reputation: 31692

Your for loop terminates after the first iteration because return terminates the function call immediately. You need to accumulate the JSX elements in an array and use that instead. You also don't need the function displayProgressBar at all.

const ProgressBar = (props) => {
  const { activeStep, totalSteps } = props;

  const steps = [];
  for (let i = 1; i <= totalSteps; i++) {
    steps.push(<div>Hello</div>);
  }
  
  return (<div className="progressBar">{ steps }</div>);
};

You should probably add an active class or something to the activeStep item so it is selected, change steps.push(...) from above to:

steps.push(<div className={ i == activeStep ? "active" : "" }>Hello</div>);

Upvotes: 4

Drew Reese
Drew Reese

Reputation: 202915

You "...have experience mapping over an array..." then this should be a cakewalk; it is exactly the same. If the question more about how to take a number and convert it to an array, and I think it is, then a common pattern is [...Array(5).keys()]. Once you've an array you can map it as normal in JSX.

const ProgressBar = (props) => {
  const { activeStep, totalSteps } = props;

  const displayProgressBar = () =>
    [...Array(totalSteps).keys()].map((step) => <div key={step}>Hello</div>);

  return <div className="progressBar">{displayProgressBar()}</div>;
};

It may be simpler to just inline the array though.

const ProgressBar = (props) => {
  const { activeStep, totalSteps } = props;

  return (
    <div className="progressBar">
      {[...Array(totalSteps).keys()].map((step) => {
        // logic to compare against activeStep
        return (
          <div key={step}>Hello</div>
        ))}}
    </div>
  );
};

Upvotes: 1

Jayce444
Jayce444

Reputation: 9063

Well you literally need an array of elements, so what's wrong with creating an array?

const ProgressBar = (props) => {
    const { activeStep, totalSteps } = props;

    const steps = (new Array(totalSteps))
        .fill(undefined)
        .map((step, index) => (
            // If the step is active (or past) step, give it a grey background
            <div key={index} style={{ backgroundColor: index + 1 <= activeStep ? 'grey' : 'white' }}>
                {index+1}
            </div>
        ));
    
    return <div className="progressBar">{steps}</div>;
};

Something like this will create an array of elements and colour them accordingly

Upvotes: 0

Gabriele Petrioli
Gabriele Petrioli

Reputation: 196026

You could create an array on the fly just for this

const ProgressBar = (props) => {
  const { activeStep, totalSteps } = props;

  const steps = new Array(totalSteps).fill().map((_,index)=>{
    const stepIndex = index+1;
    const activeClassName = stepIndex === activeStep ? 'active':undefine;
    return <div className={activeClassName}>{stepIndex}</div>
  });
  return <div className="progressBar">{display}</div>;
};

Upvotes: 0

Related Questions