0
import React, { useState, useRef } from "react";
import { Link, animateScroll as scroll } from "react-scroll";

function Acc(props) {
  const content = useRef(null);

  const [setActive, setActiveState] = useState("");
  const [setScroll, setScrollState] = useState();

  function toggle() {
    setActiveState(setActive === "" ? "active" : "");
    setScrollState(setScroll === "active" ? <Link to={id} smooth={true} duration={500} spy={true} exact={true}></Link> : );
  }

  return (
    <div className="a1" id={props.id}>
      <div className="a2">
        <div className="a3">
          <button className="button" onClick={toggle}>
            //image goes here
          </button>
        </div>
      </div>
    </div>
  );
}

export default Acc;

Why am I getting this error?

./src/components/Acc.js
SyntaxError: /Users/me/Desktop/School/aapp/src/components/Acc.js: Unexpected token (24:121)

  23 |     setRotateState(setActive === "active" ? "icon" : "icon rotate");
> 24 |     setScrollState(setScroll === "active" ? <Link to={id} smooth={true} duration={500} spy={true} exact={true}></Link> : );
     |                                                                                                                          ^
  25 |   }
  26 |
  27 |   return (

How do I fix it? The aim is to create smooth scroll action to the necessary div (classname='a1' which has an id) when the button is clicked. The button must smooth scroll as well as trigger toggle().

Any help would be greatly appreciated !

Ken White
  • 123,280
  • 14
  • 225
  • 444
  • 1
    From the look of line 23, you should not have the `:` just before the closing parenthesis - you have it on 24, but not on what is basically the same operation on line 23. It looks like a simple typo to me. – Ken White Apr 28 '21 at 00:44
  • it doesn't work even when I put an argument .. I'm not sure why –  Apr 28 '21 at 07:28
  • Unrelated to the error, but I wouldn't store jsx in state in the first place. You could just store a boolean and conditionally render the link based using that boolean. – 5eb Apr 28 '21 at 07:31
  • wdym? could you write out a snippet in the answer section? i don't mind any approach as long as the smooth scroll works xD –  Apr 28 '21 at 08:24

1 Answers1

1

The error as Ken White pointed out is because of this:

setScrollState(setScroll === "active" ? <Link to={id} smooth={true} duration={500}spy={true} exact={true}></Link> : );

Scroll to the end of the line for the problem.

If you're using a ternary statement you need to have something on the left and the right side of the colon :.

So something like this would be correct:

setScrollState(
  setScroll === "active" ? (
    <Link to={id} smooth={true} duration={500} spy={true} exact={true}></Link>
  ) : null
);

Doesn't have to be null, but you need to put something there.


Now I'm not entirely sure what you're trying to do, but from your code it seems you want to conditionally render a Link on button press. And when you press on it, the page should smooth scroll to an Element with a particular name.

Here's a simple example combining conditional rendering and smooth scrolling with react-scroll:

import React, { useState, useRef } from "react";
import { Element, Link, animateScroll as scroll } from "react-scroll";

function Acc(props) {
  const [isActive, setIsActive] = useState(false);

  function toggle() {
    setIsActive(true);
  }

  return (
    <div className="a1" id={props.id}>
      <div className="a2">
        <div className="a3">
          <button className="button" onClick={toggle}>
            show link
          </button>
          {isActive && (
            <Link
              to="scroll-to-element"
              smooth={true}
              duration={500}
              spy={true}
              exact="true"
            >
              Link
            </Link>
          )}
        </div>
      </div>
    </div>
  );
}

export default function App() {
  return (
    <div className="App">
      <Acc />
      {[...Array(100).keys()].map((el) => {
        return (
          <Element key={el} name={el} className="element">
            {el}
          </Element>
        );
      })}
      <Element name="scroll-to-element" className="element">
        Scroll to element
      </Element>
    </div>
  );
}

I've replaced your setActive and setScroll states with a single isActive state. At least for conditionally rendering the Link you don't need more than one piece of state.

sandbox example

Update

If you want the button to scroll there is no need for the Link and you could just do something like this:

import "./styles.css";
import React from "react";
import { Element, scroller } from "react-scroll";

function Acc(props) {
  function toggle(e) {
    scroller.scrollTo("scroll-to-element", {
      smooth: true,
      duration: 500,
      spy: true,
      exact: true
    });
  }

  return (
    <div className="a1" id={props.id}>
      <div className="a2">
        <div className="a3">
          <button className="button" onClick={toggle}>
            scroll
          </button>
        </div>
      </div>
    </div>
  );
}

export default function App() {
  return (
    <div className="App">
      <Acc />
      {[...Array(100).keys()].map((el) => {
        return (
          <Element key={el} name={el.toString()} className="element">
            {el}
          </Element>
        );
      })}
      <Element name="scroll-to-element" className="element">
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ut
        vulputate lectus. Nam cursus semper mauris eget mattis. In nisl nibh,
        tempus quis lorem vitae, egestas imperdiet enim. Curabitur dictum libero
        nibh, ac tempus massa tincidunt elementum. Donec condimentum lacinia
        tortor in posuere. Quisque faucibus hendrerit nibh et convallis. Sed
        lacinia, massa id eleifend cursus, mi nulla sollicitudin dolor, eu
        posuere sapien nisi et sapien. Sed pellentesque lorem sed velit vehicula
        semper. Maecenas finibus, dolor hendrerit pulvinar feugiat, sem urna
        dictum magna, placerat dignissim est lorem vitae justo. Integer non nibh
        nulla.
      </Element>
    </div>
  );
}

sandbox example

5eb
  • 14,798
  • 5
  • 21
  • 65
  • right now, your button makes a link visible, which then when clicked goes to element ... but I need that button to toggle() as well as go to element at the same time. It might be easier to imagine the button as the . This is for an expansion panel ... which when clicked expands as well as scrolls to the top. Is that possible? –  Apr 28 '21 at 11:10
  • @NickV I've updated the question with a way to scroll on button click instead of the link. But if you always want to go to the top you could use `scrollToTop` instead of `scrollTo` where you need to pass an `Element` `name`. Either way you could put the logic that expends the expansion panel in the `onClick` and after that the `scrollToTop` call. – 5eb Apr 28 '21 at 11:46
  • You could also add some state and a check so that you only scroll if the menu is closed. – 5eb Apr 28 '21 at 11:53
  • how would you add something like that? how would the state be defined in the scroller function? –  Apr 28 '21 at 12:45
  • The state itself wouldn't be intialised inside the scroller function, but you could have this `const [isActive, setIsActive] = useState(false);` like I had it in my answer before the update section. The menu would start in a non expanded state so we give `isActive` a default value of `false`. In `toggle` you could then have a check like this: `if (!isActive) { // scroll... ) }`. Then at the end of the `toggle` function you could toggle the `isActive` state with `setIsActive(!isActive)`. – 5eb Apr 28 '21 at 12:54
  • Oh great thanks! also could you please look at this and see if you can help?! Thank you! ... https://stackoverflow.com/questions/67304135/fixed-div-height-interfering-with-smooth-scroll-react-scroll –  Apr 28 '21 at 16:38