devrnt / react-use-wizard

🧙 A React wizard (stepper) builder without the hassle, powered by hooks.

Home Page:https://devrnt.github.io/react-use-wizard/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`handleStep` type to return a `boolean | void`

matand-dd opened this issue · comments

We would like to change the handleStep type to return a boolean | void. Use case where you perform logic or async calls in the handleStep which can decide if you should navigate to the next step or not.
However the repository is locked for public users it seems like so I cannot add a PR for this.

Hi, thanks for creating this issue. Strange, you should be able to create a PR.

However your request is still unclear to me, could you provide a small CodeSandbox/snippet (or some pseudo-code) to clearify your use case? It seems to me that you can just add the conditions within the handleStep callback.

Hi!

I might be able to create a PR, but I'm not able to push to your repository. 🙂 I just get a ERROR: Permission to devrnt/react-use-wizard.git denied to matand-dd. error.

However, pseudo code for what we would like to achieve would be something like this (Inside a step where we can call handleStep:

handleStep(() => { // return true and we navigate to next step, return false for staying on current step. return isValid() ? true : false; });

You should fork this repo first, clone it and then you will be able to push

commented

I forked this repo as the changes I needed were too severe for a PR.

But I had this issue myself and I solved it by changing the handleStep:

handleStep: (handler: Handler) => boolean | void

Changing the try block in wizard.tsx

try {
          setIsLoading(true)
          const res = await nextStepHandler.current()
          setIsLoading(false)

          if (!res) {
            return
          }

          nextStepHandler.current = null
          goToNextStep.current()
        }

Finally the handlestep can return a boolean

handleStep(() => {
    return false
})

@devrnt Thanks for developing this wizard. Out of the few that are out there for React. This one was the easiest to Grok and being in Typescript (others are not). Is so much better!

Oh and as to why this is needed. Imagine a form submit scenario. Only when the form is valid, should the wizard proceed to the next stage or be submitted.

I forked this repo as the changes I needed were too severe for a PR.

But I had this issue myself and I solved it by changing the handleStep:

handleStep: (handler: Handler) => boolean | void

Changing the try block in wizard.tsx

try {
          setIsLoading(true)
          const res = await nextStepHandler.current()
          setIsLoading(false)

          if (!res) {
            return
          }

          nextStepHandler.current = null
          goToNextStep.current()
        }

Finally the handlestep can return a boolean

handleStep(() => {
    return false
})

@devrnt Thanks for developing this wizard. Out of the few that are out there for React. This one was the easiest to Grok and being in Typescript (others are not). Is so much better!

Oh and as to why this is needed. Imagine a form submit scenario. Only when the form is valid, should the wizard proceed to the next stage or be submitted.

Hey there, I understand your concerns since the ambiguity with what we're discussing relies on the library's design which provides two different spots in the code where to add logic.

Depending on the type of form library you could disable the button and/or act inside the nextButton handler:

const Step1 = () => {
  const { handleStep, previousStep, nextStep } = useWizard();

  handleStep(() => {
    // You can submit here but then you would have no control over whether to navigate or not.
    submit()
  });

  return (
    <>
      <button onClick={() => previousStep()}>Previous ⏮️</button>
      <button onClick={() => nextStep()}>Next ⏭</button>
    </>
  );
};

But you can also do

const Step1 = () => {
  const {previousStep, nextStep } = useWizard();

  return (
    <>
      <button onClick={() => previousStep()}>Previous ⏮️</button>
      <button onClick={async () => {
        const res = await submit();

        if(res.ok) {
          nextStep()
        } else {
          // The form or validation is not ok
      }}>Next ⏭</button>
    </>
  );
};

Considering that prev and next buttons could be reused and might even be in the footer component which is instantiated only once, I agree that the right place to do this would be in the handleStep returning a boolean and it feels quite a hack to avoid going to the next step like this.

Edit: just saw #79, throwing an Exception solves this use case, docs weren't super clear on that for me.

Ran into the same issue. We have an async call happening to an API in handleStep but if that fails, I want to remain on the step and show an error. Right now, I have to handle this like so, also introducing separate state to track the loading, instead of being able to use the useWizard isLoading prop.

  const { nextStep } = useWizard();
  const [isLoading, setLoading] = useState(false);
  const handleStep = () => {
    setLoading(true);
    executeApiCall().then((success) => {
      setLoading(false);
      if (success) {
        nextStep();
      }
    })
  }
  return (
          <Button
            onClick={handleStep}
            order="primary"
            translationKey="next"
            iconAfter="arrow"
            disabled={isLoading}
          />
    );

Being able to do the following would be much cleaner.

  const { nextStep, handleStep, isLoading } = useWizard();
  handleStep(() => executeApiCall());
  
  return (
          <Button
            onClick={nextStep}
            order="primary"
            translationKey="next"
            iconAfter="arrow"
            disabled={isLoading}
          />
    );

Closing because #79 (comment) with the current API