Search code examples
javascriptreactjsjsxreact-scroll

Wanting to make an arrow animation to expand or collapse the link's sublinks list ReactJS


First time the function executes correctly, when clicking on button all times afterwards - no. I think it gets terminated somewhere. I think that in some of the checkpoints the value for some reason is null, and maybe that is why it isn;t executing, ebacsie first time it always executes correctly, and all times afterwards - no. And all times afterwards I don't see the console log of "Function almost finished executing"

Expected behaviour is to have an icon arrow, onClick on which will open/close the main link's sublinks list in the navigation.

Like this:

icon is ">" and link is somelink

when somelink gets clicked, the appearance of navigation I want to be like: "<" somelink link1 link2 link3 (so that submenu open)

I'm using React hooks. Please help me with that, what am I doing wrong?

    const ServiceConditions = () => {
      const [arrowIsClicked, setArrowIsClicked] = React.useState(false);
  const handleSublinksExpandCollapse = (e : React.MouseEvent<SVGSVGElement>) => {
    console.log("arrow is clicked");
    if (arrowIsClicked) return;
    setArrowIsClicked(true);
    if ((e.target as HTMLElement).style.transform === "rotate(0deg)") {
      (e.target as HTMLElement).style.transform = "rotate(180deg)";
     
      if (!e.target) console.log(e.target); return
      const parent = (e.target as HTMLElement).parentNode;
      if (!parent) console.log(e.target); return 
      const nextSibling = parent.nextSibling;
      if (!nextSibling) console.log(e.target); return 
      (nextSibling as HTMLElement).style.display = "block";
      console.log("function has almost done executing")
      setArrowIsClicked(false)
      
    } else {  setArrowIsClicked(true); (e.target as HTMLElement).style.transform = "rotate(0deg)";
    
    if (!e.target) console.log(e.target); return 
    const parent = (e.target as HTMLElement).parentNode;
    if (!parent) console.log(e.target); return 
    const nextSibling = parent.nextSibling;
    if (!nextSibling) console.log(e.target); return
    (nextSibling as HTMLElement).style.display = "none"; setArrowIsClicked(false); }
   
  }
    
      return (
          <Container>
            {    isDesktop &&
              <><NavigationContainer>
              <StyledScrollSpy
              scrollTargetIds={["section_1", "section_2", "section_3"]}
              offset={100}
              activeNavClass="is-active"
              scrollDuration="1000"
              headerBackground="true"
          >
              <List>
                  <MainRef><Line1><MainRefTypography variant="body1"><a href="#">Home</a></MainRefTypography><IconStyled id="ad-ap" onClick={(e : React.MouseEvent<SVGSVGElement>) => {handleSublinksExpandCollapse(e)}}></IconStyled></Line1><div><LinksInsideList>
                    <MainRef><LinkInsideTypography variant="body4"><a href="#section_1">Section 1</a></LinkInsideTypography></MainRef>
                  <MainRef><LinkInsideTypography variant="body4"><a href="#section_2">Section 2</a></LinkInsideTypography></MainRef>
                  <MainRef><LinkInsideTypography variant="body4"><a href="#section_3">Section 3</a></LinkInsideTypography></MainRef>
                  </LinksInsideList></div></MainRef>
                  
              </List>
              </StyledScrollSpy>
          
          </NavigationContainer></>    }
                    <Articles>
                      <PageName variant={isDesktop ? "h3" : "h1"}>SERVICE CONDITIONS</PageName>
                      <Bar align={BarAlign.Left} />
                      <Spacing mobile={3} desktop={3}/>
                        <div style={{"height": "400px", width: "100%"}}><span>Welcome!</span></div>
                        <div id="section_1" style={{"height": "500px", width: "100%"}}><span>Section 1</span></div>
                        <div id="section_2" style={{"height": "500px", width: "100%"}}><span>Section 2</span></div>
                        <div id="section_3" style={{"height": "500px", width: "100%"}}><span>Section 3</span></div>
                        </Articles>
            </Container>
      );
    };
    export default ServiceConditions;

Solution

  • Well, I think the problem is with this:

    "if (arrowIsClicked) return;"

    First it runs entirely setting arrowIsClicked to true, and afterwards at that line it exits every time.

    Here is a simple way to implement a button that has the arrow rotating based on open/close state:

    function CollapsibleButton() {
      const [open, setOpen] = useState(false);
    
      return (
        <button
          style={{
            display: "inline-block",
          }}
          // Simply setting open to the opposite value.
          onClick={() => setOpen(!open)}
        >
          <span
            style={{
              // This makes it feel animated:
              transition: "transform 200ms linear",
              // This rotates the element:
              transform: `rotateZ(${open ? 0 : "180deg"})`,
              display: "inline-block",
            }}
          >
            {"<"}
          </span>
          Click me
        </button>
      );
    }