makotot / react-scrollspy

:six_pointed_star: react scrollspy component
https://makotot.github.io/react-scrollspy/
MIT License
427 stars 82 forks source link

Not working with nested components #96

Open thebarty opened 5 years ago

thebarty commented 5 years ago

Hi guys,

can NOT get it working, when using nested component like

const AffixLink = (props) => {
  const {
    src,
    title,
    href,
  } = props
  return (
    <div className="affix-link-wrapper col-xs-2">
      <a className="affix-link" href={href}>
        <div className="affix-link-img">
          <img className="img img-responsive" src={`/images/${src}`} alt=""/>
        </div>
        <div className="affix-link-title" dangerouslySetInnerHTML={{ __html: title }}/>
      </a>
    </div>
  )
}
return (
  <div className={`affix-toc-component ${cssClasses}`}>
    <Sticky id="asd" top="#navbar">
      <div className="container">
        <div className="row">
          <Scrollspy
            items={['anchor-1', 'anchor-2', 'anchor-3', 'anchor-4', 'anchor-5']}
            currentClassName="is-active"
            componentTag="div"
          >
            <AffixLink
              href="#anchor-1"
              />
            <AffixLink
              href="#anchor-2"
            />
          </Scrollspy>
        </div>
      </div>
    </Sticky>
  </div>
)
SilencerWeb commented 5 years ago

@thebarty, I have the exact case and I'm curious if you've come up with a solution or not

thebarty commented 5 years ago

@SilencerWeb its been a while. had a look at the project I needed this for. I endet up NOT using this package. react-stickynode seems to have worked better… give it a try. Enjoy!

SilencerWeb commented 5 years ago

@thebarty, thanks for the answer! I ended up using custom vanilla JS function :)

raymond-ong commented 5 years ago

Not sure if the scenario I encountered is same as yours. I also have a nested layout (nested React Split layouts). The problem was that ScrollSpy only highlights the top link as the current scroll position.

In the end, I simply had to specify the rootEl prop. The rootEl value is also tricky because I have nested containers. The rootEl value has to be the topmost element that owns the scrollbar. return <Scrollspy items={ ['section-title', 'section-1', 'section-2', 'section-3', 'section-4']} rootEl="#homeRight" ...

CharlieGreenman commented 4 years ago

For anyone else wondering. What I decided to do is flatten the array, and create an object specifying the level and content. Something like this:

const h2H3Array = props.strapiArticles["articleSections"]
    .map(section => {
      return [
        { level: "h2", content: section["title"] },
        headingParser(section["content"])
          ? headingParser(section["content"])
          : headingParser(section["content"]),
      ].flat()
    })
    .flat()
    .filter(item => typeof item !== "undefined")

headingParser is a function I am using to parse our h3 headers form markdown. Anyways, after flattening array, it worked as expected.

frietkip commented 3 years ago

@CharlieGreenman thanks for providing your solution. However, I cannot get it working with map function and send to nested component. See https://github.com/makotot/react-scrollspy/issues/209 . Could you help me and take a look? Many thanks

CharlieGreenman commented 3 years ago

@CharlieGreenman thanks for providing your solution. However, I cannot get it working with map function and send to nested component. See https://github.com/makotot/react-scrollspy/issues/209 . Could you help me and take a look? Many thanks

Unfortunately your question is too open ended. If more specific, I could help

frietkip commented 3 years ago

Thanks for getting back to @CharlieGreenman.

As you can read in this issue I posted: https://github.com/makotot/react-scrollspy/issues/209 , I have Home component (home page) with two nested components:

  1. Navbar component which will list the articles URL the user can click on to navigate to the article
  2. Article component which will list the article content so the user navigates to this article (using # anchor link).

The ScrollSpy component does not work when I perform a map function in the Home component to generate the URLs for the NavBar component.

Home component

import NavBar from "./NavBar";
import Article from "./Article";
import React, { Component, Fragment } from "react";

class Home extends Component {
  render() {
    const { articles } = this.props;
    return (
      <Fragment>
        <div>
          {articles.map((article) => (
            <NavBar key={article.id} {...article} />
          ))}
        </div>
        <div>
          {articles.map((article) => (
            <Article key={article.id} {...article} />
          ))}
        </div>
      </Fragment>
    );
  }
}

export default Home;
  1. NavBar component
    
    import React, { Fragment, Component } from 'react'
    import Scrollspy from 'react-scrollspy'

class NavBar extends Component { render() { const {id, title} = this.props return (

    )
}

}

export default NavBar


2. Article component

import React, { Component } from 'react'

class Article extends Component { render() { const {id, title, body} = this.props return (

{title}

{body}

    )
}

}

export default Article



If I manually type all the articles (without map function) in the NavBar component it works but when using the map function the ScrollSpy component doesn't work anymore.

Any advice or tips are welcome! If you require more code or details let me know! Many thanks 
mochoy commented 3 years ago

I also went for a similar approach as @CharlieGreenman, I flattened my array and everything works like a charm. My jsx doesn't have the same nested structure, so I encoded the hierarchy of my tree/data by applying classnames based on my desired hierarchy of the actual data. Luckily I didn't need complex styling or that nested structure, so it was much more straightforward for me.