0

I learn React and wanted to get react-router-dom working but something is wrong in the code

Basically I have a click on an image that goes here:

onImageClick = val => {
   return(
    <Link
    to={{
      pathname: "/timeLineViewer",
      productdetailProps: {
       productdetail: {val.week }
      }
      }}>
     </Link>
     )
  };

But the Link should call TimeLineViewer constructor but its not working

Here is App

import React, { Component } from "react";
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'

import Header from "./components/structure/Header";
import Content from "./components/structure/Content";
import Footer from "./components/structure/Footer";
import TimeLineViewer from './components/sections/TimeLineViewer'

class App extends Component {

  render() {
    return (
      <Router>
      <div>
        <Header />
        <Content />
        <Footer />
      </div>
      <Switch>
        <Route path="/timeLineViewer">
          <TimeLineViewer />
        </Route>
      </Switch>
    </Router>
    );
  }
}

export default App;

Please advice I'm new to React

UPDATE Here is the Component that has the onImageClick

//import Timeline from "../elements/Timeline";
import Slider from "react-slick";
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";
import React, { Component } from "react";
import Resume from "../../resume.json";
import TimeLineViewer from "./TimeLineViewer"
import { Link } from 'react-router-dom'

export default class Timeline extends React.Component {

    constructor(props) {
        super(props)
        this.changeHandler = this.changeHandler.bind(this)
        this.changeSlider = this.changeSlider.bind(this)
        this.state = {
            slideIndex: 0,
            updateCount: 0,
            settings: {
                dots: false,
                infinite: true,
                speed: 500,
                slidesToShow: 1,
                slidesToScroll: 1,
                afterChange: () =>
                    this.setState(state => ({ updateCount: state.updateCount + 1 })),
                beforeChange: (current, next) => this.setState({ slideIndex: next })
            }
        }
    }

    changeHandler(e) {
        this.sliderWrapper.slider.slickGoTo(e.target.value)
    }

    changeSlider() {
        this.setState({
            slideIndex: this.sliderWrapper.slider.innerSlider.state.currentSlide
        })
    }

    changeUpdateCount(e) {
        this.setState({
            updateCount: this.state.updateCount + 1
        }, () => console.log(`test state after update: ${this.state.updateCount}`))
    }

    onImageClick = val => {
       // TimeLineViewer={val.week}
       return(
        <Link
        to={{
          pathname: "/timeLineViewer",
          productdetailProps: {
           productdetail: "I M passed From Props"
          }
       }}>
         </Link>
         )
      };

    render() {
        return (
            <div className="container" id="timeline">
                <h2>Slick Go To</h2>
                <p>Total updates: {this.state.settings.updateCount} </p>
                <input onChange={this.changeHandler} value={this.state.slideIndex} type='range' min={0} max={3} />
                <SliderWrapper onImageClick={this.onImageClick}
                    ref={sliderWrapper => this.sliderWrapper = sliderWrapper}
                    beforeChange={this.changeUpdateCount.bind(this)}
                    afterChange={this.changeSlider.bind(this)}
                    slideIndex={this.state.slideIndex}
                    updateCount={this.state.updateCount}
                />
            </div>
        );
    }
}


class SliderWrapper extends React.Component {

    shouldComponentUpdate(nextProps, nextState) {
        // certain condition here, perhaps comparison between this.props and nextProps
        // and if you want to update slider on setState in parent of this, return true, otherwise return false
        if (this.props.updateCount !== nextProps.updateCount) {
            return false
        }
        return true
    }

    sliders() {
        return Resume.weeks.map(week => {
            return (
                // Timeline items
                <section className="timeline-carousel">
                    <h1>week {week.week}</h1>
                    <div className="timeline-carousel__item-wrapper" data-js="timeline-carousel">
                        <div className="timeline-carousel__item">
                            <div key={week} className="timeline-carousel__image">
                                <img onClick={() => this.props.onImageClick(week)} alt="image" src={week.frontImage}  />
                                <h2>UNDER CONSTRUCTION IN PROGRES..</h2>
                            </div>
                            <div className="timeline-carousel__item-inner">
                            <div className="pointer" />
                                <span className="year">{week.year}</span>
                                <span className="month">{week.albumDate}</span>
                                <p>{week.summary}</p>
                                <a href="#" className="read-more">Read more</a>
                            </div>
                        </div>
                    </div>
                </section>
             )
        });
    }

    render() {
        const settings = {
            dots: false,
            infinite: false,
            speed: 100,
            slidesToShow: 4,
            slidesToScroll: 1,
            afterChange: this.props.afterChange,
            beforeChange: this.props.beforeChange,
            responsive: [
                {
                  breakpoint: 700,
                  settings: {
                    arrows: false,
                    slidesToShow: 3
                  }
                },
                {
                  breakpoint: 500,
                  settings: {
                    arrows: false,
                    slidesToShow: 2
                  }
                },
                {
                  breakpoint: 400,
                  settings: {
                    arrows: false,
                    slidesToShow: 1
                  }
                }
            ]
        };
        return (
            <div >
                <Slider ref={slider => this.slider = slider} {...settings}>
                    {this.sliders()}
                </Slider>
            </div>
        );


    }
}

UPDATE Here's an image what it looks like enter image description here

Kid
  • 1,869
  • 3
  • 19
  • 48

2 Answers2

1

Can you change this

        <Route path="/timeLineViewer">
          <TimeLineViewer />
        </Route>

To this

        <Route path="/timeLineViewer" component={TimeLineViewer} />
  • Thanks I think I do something wrong because the TimeLineViewer Component is already loaded and visible in the doom so constructor has already been fired. How to pass this props to it? – Kid Aug 12 '20 at 12:00
  • 1
    I think this link solves your problem https://stackoverflow.com/questions/30115324/pass-props-in-link-react-router – yagizhan.avci Aug 12 '20 at 12:38
1

I think in your case you have something like that in your codebase

const Container = () => {
...
return (
...
  <img src="..." onClick={onImageClick = val => {
   return(
    <Link
      to={{
        pathname: "/timeLineViewer",
        productdetailProps: {
        productdetail: {val.week }
        }
       }} />
     )
  };}/>
...
)
}

It's wrong because if you want to redirect onClick you need to use history API https://reactrouter.com/web/api/Hooks/usehistory If you put Link in return of onClick event, it can't reach JSX and never renders. So if Link wasn't rendered it shouldn't work)

Also you can wrap your image with link

const Container = () => {
...
return (
...

   <Link
      to={{
        pathname: "/timeLineViewer",
        productdetailProps: {
        productdetail: {val.week }
        }
       }}>
      <img src="..." />
   </Link>
     )
  };}/>
...
)
}

UPDATE Something like that should work

...
import { withRouter } from "react-router";

class Timeline extends React.Component {

....
    onImageClick = val => {
        const {history} = this.props;
       // TimeLineViewer={val.week}
       history.push("/timeLineViewer", {productdetailProps: {
           productdetail: "I M passed From Props"
          }});
      };

    ....
    }
}

export default withRouter(Timeline)
Boykov
  • 374
  • 1
  • 6
  • Thanks I updated my question, the `onImageClick` is just a function – Kid Aug 12 '20 at 11:58
  • 1
    In your case you need to use history. You can add it to your component by HOC https://reactrouter.com/web/api/withRouter. – Boykov Aug 12 '20 at 12:00
  • Added sample for withRouter and history – Boykov Aug 12 '20 at 12:04
  • Thanks looks like it working but only on first click. The TimeLineViewer Constructor is getting the props but clicking again Constructor is not running. I know of course it's only run on creating the component. – Kid Aug 12 '20 at 12:30
  • I added a picture to my question to illustrate – Kid Aug 12 '20 at 12:31
  • Can you add sandbox example? Also yagizhan.avci comment under first answer could help you) – Boykov Aug 12 '20 at 12:55
  • Thanks I created a [sandbox](https://codesandbox.io/s/gretas-site-carousel-tex-not-straight-75nwm?file=/src/TimeLineViewer.js) Look at the image above in my post to see how it works – Kid Aug 12 '20 at 16:19
  • 1
    When you click on different images url never changes, You need to add query params to your link to make it work. @yagizhan.avci added link to a solution for your question) take a look at https://stackoverflow.com/questions/30115324/pass-props-in-link-react-router – Boykov Aug 12 '20 at 16:28
  • ok It works now I'm new to React. When using your code the render method in TimeLineViewer does fire. – Kid Aug 12 '20 at 18:12