Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

react router changes the URL, but the component is not rendered

I have a component that consumes an API and renders a list. Each list item has a custom link to redirect to it's page.

I'm trying to make this route getting the URL params, to show the other component.

But despite the URL changes, the other component is never rendered when I click the list item. But the funny thing is that if I type the URL manually, it renders.

Here goes my code:

App.js

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

// import Routes from "./routes";
import Navbar from "./components/Navbar";
import GlobalStyle from "./styles/global";

import Main from "./pages/Main";
import Hero from "./pages/Hero";
import Favorites from "./pages/Favorites";

const App = () => (
  <Router>
    <GlobalStyle />
    <Navbar />
    <ul>
      <li>
        <Link to="/">Home</Link>
      </li>
      <li>
        <Link to="/favorites">Favoritos</Link>
      </li>
    </ul>
    <Switch>
      {/* <Main path="/hero/:heroId" component={Hero} /> */}
      <Route path="/hero" component={Hero} />
      <Route path="/favorites" component={Favorites} />
      <Route path="/" exact component={Main} />

      {/* <Route path="/hero" render={props => <Hero {...props} />} /> */}
    </Switch>
  </Router>
);
export default App;

Main.js

import React, { Component } from "react";
import { BrowserRouter as Router, Link } from "react-router-dom";
import api from "../../services/api";
import md5 from "js-md5";

import { SearchBar, SearchInput, SearchButton, Wrapper } from "./styles";

import Card from "../../components/Card";

export default class Main extends Component {
  constructor(props) {
    super(props);
    this.state = {
      heroes: [],
      search: ""
    };

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  componentDidMount() {
    this.loadHeroes();
  }

  componentDidUpdate(prevProps, prevState) {
    if (prevState.searc !== this.state.search) {
      this.loadHeroes();
    }
  }

  loadHeroes = async () => {
    const PUBLIC_KEY = process.env.REACT_APP_PUBLIC;
    const PRIVATE_KEY = process.env.REACT_APP_PRIVATE;
    const timestamp = Number(new Date());
    const hash = md5.create();
    hash.update(timestamp + PRIVATE_KEY + PUBLIC_KEY);

    if (this.state.search === "") {
      await api
        .get(`/characters?ts=${timestamp}&apikey=${PUBLIC_KEY}&hash=${hash}`)
        .then(response =>
          this.setState({ heroes: response.data.data.results })
        );
    } else {
      await api
        .get(
          `/characters?nameStartsWith=${this.state.search}&ts=${timestamp}&apikey=${PUBLIC_KEY}&hash=${hash}`
        )
        .then(response =>
          this.setState({ heroes: response.data.data.results })
        );
    }
  };

  handleChange(event) {
    this.setState({ search: event.target.value });
  }

  handleSubmit(event) {
    console.log("State do search: ", this.state.search);
    event.preventDefault();
  }

  render() {
    const { heroes } = this.state;

    let filteredHeroes = heroes.filter(
      hero => hero.name.toLowerCase().indexOf(this.state.search) !== -1
    );

    return (
      <div>
        <SearchBar onSubmit={this.handleSubmit}>
          <label>
            Buscar
            <SearchInput
              onChange={this.handleChange}
              type="search"
              value={this.state.search}
            />
          </label>
          <SearchButton type="submit" value="Enviar" />
        </SearchBar>

        <Router>
          <Wrapper>
            {filteredHeroes.map(hero => {
              return (
                <Link
                  to={`hero?q=${hero.id}`}
                  style={{ textDecoration: "none" }}
                  key={hero.id}
                >
                  <Card name={hero.name} thumbnail={hero.thumbnail} />
                </Link>
              );
            })}
          </Wrapper>
        </Router>
      </div>
    );
  }
}

Hero.js

import React from "react";

const Hero = props => {
  return (
    <div>
      <h1>{props.name}</h1>

      <article>
        <p>
          Lorem ipsum dolor, sit amet consectetur adipisicing elit. Minima
          accusamus ducimus qui amet quis? Non rerum consequuntur soluta,
          voluptatum blanditiis explicabo, laudantium architecto distinctio enim
          aliquid placeat, quaerat voluptas totam!
        </p>
      </article>
    </div>
  );
};

export default Hero;

like image 345
Marcelo Melo Avatar asked Sep 18 '25 23:09

Marcelo Melo


1 Answers

Make following changes in your code !

App.js

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

// import Routes from "./routes";
import Navbar from "./components/Navbar";
import GlobalStyle from "./styles/global";

import Main from "./pages/Main";
import Hero from "./pages/Hero";
import Favorites from "./pages/Favorites";

const App = () => (
  <Router>
    <GlobalStyle />
    <Navbar />
    <ul>
      <li>
        <Link to="/">Home</Link>
      </li>
      <li>
        <Link to="/favorites">Favoritos</Link>
      </li>
    </ul>
    <Switch>
      <Route path="/" exact component={Main} />
      <Route path="/hero" exact component={Hero} />
      <Route path="/favorites" exact component={Favorites} />
    </Switch>
  </Router>
);
export default App;

Main.js

import React, { Component } from "react";
import { BrowserRouter as Router, Link } from "react-router-dom";
import api from "../../services/api";
import md5 from "js-md5";

import { SearchBar, SearchInput, SearchButton, Wrapper } from "./styles";

import Card from "../../components/Card";

export default class Main extends Component {
  constructor(props) {
    super(props);
    this.state = {
      heroes: [],
      search: ""
    };

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  componentDidMount() {
    this.loadHeroes();
  }

  componentDidUpdate(prevProps, prevState) {
    if (prevState.searc !== this.state.search) {
      this.loadHeroes();
    }
  }

  loadHeroes = async () => {
    const PUBLIC_KEY = process.env.REACT_APP_PUBLIC;
    const PRIVATE_KEY = process.env.REACT_APP_PRIVATE;
    const timestamp = Number(new Date());
    const hash = md5.create();
    hash.update(timestamp + PRIVATE_KEY + PUBLIC_KEY);

    if (this.state.search === "") {
      await api
        .get(`/characters?ts=${timestamp}&apikey=${PUBLIC_KEY}&hash=${hash}`)
        .then(response =>
          this.setState({ heroes: response.data.data.results })
        );
    } else {
      await api
        .get(
          `/characters?nameStartsWith=${this.state.search}&ts=${timestamp}&apikey=${PUBLIC_KEY}&hash=${hash}`
        )
        .then(response =>
          this.setState({ heroes: response.data.data.results })
        );
    }
  };

  handleChange(event) {
    this.setState({ search: event.target.value });
  }

  handleSubmit(event) {
    console.log("State do search: ", this.state.search);
    event.preventDefault();
  }

  render() {
    const { heroes } = this.state;

    let filteredHeroes = heroes.filter(
      hero => hero.name.toLowerCase().indexOf(this.state.search) !== -1
    );

    return (
      <div>
        <SearchBar onSubmit={this.handleSubmit}>
          <label>
            Buscar
            <SearchInput
              onChange={this.handleChange}
              type="search"
              value={this.state.search}
            />
          </label>
          <SearchButton type="submit" value="Enviar" />
        </SearchBar>
          <Wrapper>
            {filteredHeroes.map(hero => {
              return (
                <Link
                  to={`/hero?q=${hero.id}`}
                  style={{ textDecoration: "none" }}
                  key={hero.id}
                >
                  <Card name={hero.name} thumbnail={hero.thumbnail} />
                </Link>
              );
            })}
          </Wrapper>
      </div>
    );
  }
}

and no need to change in Herocomponent.

like image 175
Danish Avatar answered Sep 20 '25 18:09

Danish