4

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?

2
  • 1
    Your function can only return once. If you want multiple elements in that return, you'll need to build up an array or some other data structure and return that. Commented Nov 3, 2020 at 0:50
  • as @jmargolisvt said, you can build up an array dynamically first. let arr = []; for (let i = 0; i < totalSteps; i++) arr.push(null); and then use map Commented Nov 3, 2020 at 1:06

4 Answers 4

4

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>);
Sign up to request clarification or add additional context in comments.

Comments

1

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>
  );
};

Comments

0

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>;
};

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.