Reputation: 107
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;
Upvotes: 4
Views: 5381
Reputation: 912
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.
Upvotes: 2
Reputation: 393
you need to make two changes
in you Main.js
<Link
to={`hero/${hero.id}`}
style={{ textDecoration: "none" }}
key={hero.id}
>
<Card name={hero.name} thumbnail={hero.thumbnail} />
</Link>
and in your routes, add another route or change existing to
<Route path="/hero/:heroId" component={Hero} />
Hope this would help. Extract your heroID using
props.match.params.heroId
Upvotes: 0