0

I want to create a stepper in a form that when you click the next button it's controlled by a useState that sets the current step to true or false. I know I could do this without a map function or by repeating myself with a series of map functions but I don't want that. I want to be able to add as many steps as I want without needing to hard code it in the frontend. any ideas how to connect the index in the map with the current useState inside the if-statement ?

Thanks!


export default function Steps() {
  const [stepsDone, setStepsDone] = useState({
    step1: false,
    step2: false,
    step3: false,
    step4: false,
    step5: false,
    step6: false,
  });

  return (
    <>
      <Flex flexDir="column">
        {steps.map((data, i, arr) => {
          if (arr.length - 1 === i) {
            console.log(arr[5]);
            if (stepsDone.step6) {
              return (
                <Flex flexDir="column">
                  <Flex
                    alignItems="center"
                    justifyContent="center"
                    backgroundColor="white"
                    border="2px solid #31C3AC"
                    w="52px"
                    h="52px"
                    borderRadius="50%"
                    marginBottom="11px"
                  >
                    <Image h="19px" w="20px" alt="check-mark" src={check} />
                  </Flex>
                </Flex>
              );
            }
            return (
              <Flex flexDir="column">
                <Flex
                  alignItems="center"
                  justifyContent="center"
                  backgroundColor="white"
                  border="2px solid #CECECE"
                  w="52px"
                  h="52px"
                  borderRadius="50%"
                  //   isActive={stepsDone === index ? true : false}
                  _active={{}}
                >
                  {data.number}
                </Flex>
              </Flex>
            );
          } else if (stepsDone.step5) {
            return (
              <Flex flexDir="column">
                <Flex
                  alignItems="center"
                  justifyContent="center"
                  backgroundColor="white"
                  border="2px solid #31C3AC"
                  w="52px"
                  h="52px"
                  borderRadius="50%"
                  marginBottom="11px"
                >
                  <Image h="19px" w="20px" alt="check-mark" src={check} />
                </Flex>

                <Center marginBottom="11px" h="45px">
                  <Divider
                    borderWidth={"1px"}
                    borderColor={"#31C3AC"}
                    orientation="vertical"
                  />
                </Center>
              </Flex>
            );
          } else {
            return (
              <Flex flexDir="column">
                <Flex
                  flexDir="column"
                  alignItems="center"
                  justifyContent="center"
                  backgroundColor="white"
                  border="2px solid #CECECE"
                  w="52px"
                  h="52px"
                  borderRadius="50%"
                  marginBottom="11px"
                >
                  {data.number}
                </Flex>

                <Center marginBottom="11px" h="45px">
                  <Divider
                    borderWidth={"1px"}
                    borderColor={"#CECECE"}
                    orientation="vertical"
                  />
                </Center>
              </Flex>
            );
          }
        })}
      </Flex>
      <Button
        onClick={() => {
          //   steps[5].isComplete = true;
          setStepsDone({ ...stepsDone, step5: false });
        }}
      >
        Click meeeeeee
      </Button>
    </>
  );
}
Nathan
  • 73,987
  • 14
  • 40
  • 69
Rogestav
  • 65
  • 2
  • 8

1 Answers1

1

You can use an object with the index as the key as your state, with the logic that an undefined value means false, and update only a portion of that object when you update state.

const [stepsDone, setStepsDone] = useState({})

Within the map when you need to access the state, you can do something like

const isDone = stepsDone[index] === true
// if you haven't set that step at all it'll be undefined, which is fine,
// as that's !== true

And when you complete a step, you can set

const stepIndex = 0 // first step
// we pass a callback to our set state function, to safely update
setStepsDone(previousState => { ...previousState, [stepIndex]: true });

You can of course offset the index by 1 if you want steps to start at 1 instead of 0 in the state object, but I'll leave that as an exercise to the reader.

Nathan
  • 73,987
  • 14
  • 40
  • 69
  • stepsDone[index] comes back undefined... – Rogestav Aug 01 '22 at 09:17
  • That's fine, read my code examples again. You can just use logic so that undefined is interpreted as false (the step isn't done, since it has never been defined as done). Since undefined is a falsey, you can just check if it's equal to true, and it's not done otherwise. – Nathan Aug 01 '22 at 15:28