Home > Back-end >  how to update progress bar from states in different components in React
how to update progress bar from states in different components in React

Time:08-24

I have an app I am building that has a progress bar in the footer. The HTML and CSS is perfect, I just don't know how to add functionality. Here's is the html for the bar:

     <section className="3xl:scale-125">
       <ul >
           <li >
               <span >1</span>
               <span >Get started</span>
           </li> 
           <li >
               <span >2</span>
               <span >Connect to Metamask</span>
           </li>
           <li >
               <span >3</span>
               <span >Connect to Polygon</span>
           </li>
           <li >
               <span >4</span>
               <span >Claim NFT</span>
           </li>
       </ul>
   </section>
   </div>

current-item is how the progress bar knows how it should update the css. What I need to do is add current-item to each <li> somehow, based on states (or even onClicks if that is easier) in 3 different components.

I tried to figure out how to do it with react useContext, but the problem is is that the states aren't coming from 1 single component. Any advice would be greatly appreciated!

If you need more info I can share a repo.

CodePudding user response:

Create a container and use a React.useSatate.

const [step,setActiveStep]=useState(0)
<PogressContainer>
  {stepsComponents[step]}
  <ProgressBar activeStep={step}/>
</PorgressContainer>

stepsComponents=[
<Step1 activeStep={step}/>,
<Step2 activeStep={step}/>,
<Step3 activeStep={step}/>]

It's just an idea.

CodePudding user response:

To use a context in multiple components, you need to provide it on a higher level.

You can include an update function to update the context, then consumers can use it, as outlined in the docs: https://reactjs.org/docs/context.html#updating-context-from-a-nested-component

type ProgressBar = {
  currentItem: number;
  updateCurrentItem: (item: number) => void;
};

export const ProgressBarContext: Context<ProgressBar> = createContext({});

export default function App() {
  const [progressBar, setProgressBar] = useState({
    currentItem: 0,
    updateCurrentItem: (i: number) =>
      setProgressBar((prev) => ({ ...prev, currentItem: i })),
  });

  return (
    <ProgressBarContext.Provider value={progressBar}>
      <MakeProgress />
      <ProgressBar />
    </ProgressBarContext.Provider>
  );
}

You can update the current item from any component like so:

export default function MakeProgress() {
  return (
    <ProgressBarContext.Consumer>
      {({ updateCurrentItem }) => (
        <div>
          <button onClick={() => updateCurrentItem(1)}>Complete 1</button>
          <button onClick={() => updateCurrentItem(2)}>Complete 2</button>
          <button onClick={() => updateCurrentItem(3)}>Complete 3</button>
          <button onClick={() => updateCurrentItem(4)}>Complete 4</button>
        </div>
      )}
    </ProgressBarContext.Consumer>
  );
}

To read the current item, it is basically the same. You can dynamically change the class list using className.

export default function ProgressBar() {
  return (
    <ProgressBarContext.Consumer>
      {({ currentItem }) => (
        <ul>
          <li className={currentItem >= 1 ? 'current-item' : ''}>1</li>
          <li className={currentItem >= 2 ? 'current-item' : ''}>2</li>
          <li className={currentItem >= 3 ? 'current-item' : ''}>3</li>
          <li className={currentItem >= 4 ? 'current-item' : ''}>4</li>
        </ul>
      )}
    </ProgressBarContext.Consumer>
  );
}

Stackblitz: https://stackblitz.com/edit/react-ts-4pttoq?file=App.tsx

  • Related