Dynamic data showing undefined - javascript

in my project, I'm trying, when I click a blog in many blogs. then only that blog will open in another route. and I set that route dynamically. and trying to load data using the find method. but that showing undefined. Please help me. below are my all codes.
this is my blogs page
import React, { useEffect, useState } from "react";
import { Card, Col, Row } from "react-bootstrap";
import { Swiper, SwiperSlide } from "swiper/react";
import "swiper/css";
import "swiper/css/pagination";
import { Pagination } from "swiper";
import "./Blog.css";
import ScrollToTop from "react-scroll-to-top";
import { HashLoader } from "react-spinners";
import { Link } from "react-router-dom";
const Blogs = () => {
const [blogs, setBlogs] = useState([])
useEffect(() => {
fetch('https://enigmatic-crag-58614.herokuapp.com/blogs')
.then(res => res.json())
.then(data=>setBlogs(data))
},[])
console.log(blogs);
return (
<div className="container my-5">
<ScrollToTop smooth color="#FE1A00" viewBox="0 0 250 250" />
<h1 className="text-danger">Blogs</h1>
{blogs.length === 0 && (
<h1 className="my-5 py-5">
<HashLoader color={'#FE1A00'} loading={true} size={150} />
</h1>
)}
<Row xs={1} md={3} className="g-4">
{
blogs.map(blog => <Col>
<Card className="shadow">
<Card.Img
variant="top"
src={blog.imageLink}
className="m-3"
/>
<Card.Body>
<h3 className="text-danger">{blog.heading}</h3>
<Card.Text>
{blog.text.slice(0, 200)}...
</Card.Text>
</Card.Body>
<strong className="mb-3">
<Link to={`/single-blog/${blog._id}`} className="see-more">
See More <i className="fas fa-arrow-circle-right"></i>{" "}
</Link>
</strong>
</Card>
</Col>)
}
</Row>
</div>
);
};
export default Blogs;
This is my single blog page
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import "./SingleBlog.css";
const SingleBlog = () => {
const { id } = useParams;
const [singleData, setSingleData] = useState([])
useEffect(() => {
fetch('https://enigmatic-crag-58614.herokuapp.com/blogs')
.then(res => res.json())
.then(data => setSingleData(data))
}, [])
console.log(singleData);
const matchedData = singleData.find((singleBlogPost) => singleBlogPost?._id == id)
console.log(matchedData);
return (
<div className="single-blog container w-75">
<div className="image-div mb-5 p-0">
<img
src="https://upload.wikimedia.org/wikipedia/commons/thumb/3/3f/Walking_tiger_female.jpg/220px-Walking_tiger_female.jpg"
alt=""
/>
</div>
<div>
<h1 className="text-danger">Tiger</h1>
<p className="text-start fs-5 fw-700">
The tiger (Panthera tigris) is the largest living cat species and a member of
the genus Panthera. It is most recognisable for its dark vertical stripes on
orange fur with a white underside. An apex predator, it primarily preys on
ungulates such as deer and wild boar. It is territorial and generally a solitary
but social predator, requiring large contiguous areas of habitat, which support
.
</p>
</div>
</div>
);
};
export default SingleBlog;
This is my app.js file
import "./App.css";
import Navigation from "./Components/Navigation/Navigation";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import HomePage from "./Components/HomePage/HomePage";
import AcdmClass from "./Components/AcademicClass/AcdmClass";
import ClassSubject from "./Components/ClassSubjects/ClassSubject";
import Lesson from "./Components/Lesson";
import Footer from "./Components/Footer/Footer";
import Contact from "./Components/Contact/Contact";
import Review from "./Components/Review/Review";
import Blogs from "./Components/Blog/Blogs";
import Signin from "./Components/Signin/Signin";
import Profile from "./Components/Profile/Profile";
import Skills from "./Components/Skills/Skills";
import AuthProvider from "./Contexts/AuthProvider";
import PrivateRoute from "./Components/PrivateRoute/PrivateRoute";
import SingleBlog from "./Components/SingleBlog/SingleBlog";
function App() {
return (
<div className="App">
<AuthProvider>
<BrowserRouter>
<Navigation></Navigation>
<Routes>
<Route path="/" element={<HomePage></HomePage>}></Route>
<Route path="home" element={<HomePage></HomePage>}></Route>
<Route path="blog" element={<Blogs></Blogs>}></Route>
<Route path="contact" element={<Contact></Contact>}></Route>
<Route path="skills" element={<Skills />}></Route>
<Route path="others" element={<Skills />}></Route>
<Route
path="/academic-class"
element={
<PrivateRoute>
<AcdmClass />
</PrivateRoute>
}
/>
<Route
path="/academicclass/:classnumber"
element={
<PrivateRoute>
<ClassSubject />
</PrivateRoute>
}
/>
<Route
path="/lesson"
element={
<PrivateRoute>
<Lesson />
</PrivateRoute>
}
/>
<Route
path="/profile"
element={
<PrivateRoute>
<Profile />
</PrivateRoute>
}
/>
<Route
path="/review"
element={
<PrivateRoute>
<Review />
</PrivateRoute>
}
/>
<Route
path="/single-blog/:id"
element={
<PrivateRoute>
<SingleBlog />
</PrivateRoute>
}
/>
<Route path="/sign-in" element={<Signin />} />
</Routes>
<Footer></Footer>
</BrowserRouter>
</AuthProvider>
</div>
);
}
export default App;
But showing this undefined please see this image

Try putting it in a useEffect like so
useEffect(()=>{
if(singleData){
console.log(singleData);
const matchedData = singleData.find((singleBlogPost) => singleBlogPost?._id == id)
console.log(matchedData);
}
},[singleData,id])
As initially singleData will be undefined and will be set after API call.

In react, The state of the component only get updated at the first time, So you need to tell the react to get the updated state.
In your singleBlog file -
const [singleData, setSingleData] = useState([])
useEffect(() => {
fetch('https://enigmatic-crag-58614.herokuapp.com/blogs')
.then(res => res.json())
.then(data => setSingleData(data))
}, [])
console.log(singleData);
const matchedData = singleData.find((singleBlogPost) => singleBlogPost?._id == id) //This line will never get the data until you ask the react to update the state (means to update the ```singleData``` array.
console.log(matchedData);
So you need to put the same method inside useEffect, and let the useEffect run whenever the state singleData get updated like this ->
useEffect(() => {
const matchedData = singleData.find((singleBlogPost) =>
singleBlogPost?._id == id)
console.log(matchedData);
}, [singleData, id]) //you need to add here all the dependencies, so that whenever these values will change you need to update your singleBlog page.
HERE IS YOUR FINAL CODE OF SINGLE BLOG PAGE ->
const SingleBlog = () => {
const { id } = useParams;
const [singleData, setSingleData] = useState([])
useEffect(() => {
fetch('https://enigmatic-crag-58614.herokuapp.com/blogs')
.then(res => res.json())
.then(data => setSingleData(data))
}, [])
useEffect(() => {
const matchedData = singleData.find((singleBlogPost) =>
singleBlogPost?._id == id)
console.log(matchedData);
}, [singleData, id])
return (
<div className="single-blog container w-75">
<div className="image-div mb-5 p-0">
<img
src="https://upload.wikimedia.org/wikipedia/commons/thumb/3/3f/Walking_tiger_female.jpg/220px-Walking_tiger_female.jpg"
alt=""
/>
</div>
<div>
<h1 className="text-danger">Tiger</h1>
<p className="text-start fs-5 fw-700">
The tiger (Panthera tigris) is the largest living cat species and a member of
the genus Panthera. It is most recognisable for its dark vertical stripes on
orange fur with a white underside. An apex predator, it primarily preys on
ungulates such as deer and wild boar. It is territorial and generally a solitary
but social predator, requiring large contiguous areas of habitat, which support
.
</p>
</div>
</div>
);
};
export default SingleBlog;

Related

How can i get some value from other page js?

I have two page: Header.js and Post.js. These pages is joined on main page - Home.js. Post.js has button "Buy". This button creates variable with value 0 or 1. This value is saved on local storage with window.localStorage.setItem(). And I Want to take with value and give to Header.js. But when I do this value isn't updated avere time, when I click "buy"
How can I make this?
window.localStorage.setItem('countcart',count);
const sumCount = async () => {
if(count === 0){
setCount(Math.max(count+1,0));
} else{
setCount(Math.max(count-1,0));
}
};
<Button className={styles.buy} onClick={sumCount} variant="contained" endIcon={<ShoppingCartIcon fontSize="small"/>}><div className={styles.buytext}>Buy</div> </Button>
If you want localStorage to update every time count is changed, you should wrap it with a useEffect:
useEffect(() => {
window.localStorage.setItem('countcart',count);
}, [count])
But, this doesn't auto-update the count value in the other component; to do that with localStorage you'd need to use the https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event
But, a better way for the other component to access count would be to declare count as a state in the parent component and pass its state to the Header.js and Post.js components, e.g.:
// App.js
function App() {
const [count, setCount] = useCount(window.localStorage.getItem('count'));
useEffect(() => {
window.localStorage.setItem('countcart',count);
}, [count])
return (
<>
<Header count={count} setCount={setCount} />
<Post count={count} setCount={setCount} />
</>
)
}
import {Routes, Route} from 'react-router-dom';
import Container from '#mui/material/Container';
import { Header } from './components';
import { Home, FullPost, Registration, AddPost, Login, PostsByTag, Account } from './pages';
import { useDispatch, useSelector } from 'react-redux';
import React, { useState } from 'react';
import { fetchAuthMe, selectIsAuth } from './redux/slices/auth';
function App() {
const dispatch = useDispatch();
const [count, setCount] = useState(window.localStorage.getItem('countcart')? 0 :window.localStorage.getItem('countcart'));
const isAuth = useSelector(selectIsAuth);
React.useEffect(()=>{
dispatch(fetchAuthMe());
window.localStorage.setItem('countcart',count);
},[count])
return (
<>
<Header count={count} setCount={setCount}/>
<Container maxWidth="lg">
<Routes>
<Route path="/" element={<Home count={count} setCount={setCount}/>} />
<Route path="/posts/:id" element={<FullPost />} />
<Route path="/tags/:tag" element={<PostsByTag />} />
<Route path="/posts/:id/edit" element={<AddPost />} />
<Route path="/add-post" element={<AddPost />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Registration />} />
<Route path="/account/:id" element={<Account />} />
</Routes>
</Container>
</>
);
}
export default App;
import React from 'react';
import { Rating,IconButton, Button} from '#mui/material';
import clsx from 'clsx';
import {Link, useNavigate} from 'react-router-dom';
import DeleteIcon from '#mui/icons-material/Clear';
import EditIcon from '#mui/icons-material/Edit';
import EyeIcon from '#mui/icons-material/RemoveRedEyeOutlined';
import CommentIcon from '#mui/icons-material/ChatBubbleOutlineOutlined';
import ShoppingCartIcon from '#mui/icons-material/ShoppingCart';
import styles from './Post.module.scss';
// import { UserInfo } from '../UserInfo';
import { PostSkeleton } from './Skeleton';
import { useDispatch } from 'react-redux';
import { fetchRemovePost } from '../../redux/slices/posts';
export const Post = ({
id,
title,
createdAt,
imageUrl,
user,
viewsCount,
commentsCount,
tags,
children,
isFullPost,
isLoading,
isEditable,
count,
setCount,
}) => {
// const [count, setCount] = React.useState(0);
const dispatch = useDispatch();
const navigate = useNavigate();
if (isLoading) {
return <PostSkeleton />;
}
console.log(count);
window.localStorage.setItem('countcart',count);
const sumCount = async () => {
if(count === 0){
setCount(Math.max(count+1,0));
} else{
setCount(Math.max(count-1,0));
}
};
const onClickRemove = () => {
if(window.confirm('Do you sure want to remove post?')){
dispatch(fetchRemovePost(id));
navigate(0);
}
};
return (
<div className={clsx(styles.root, { [styles.rootFull]: isFullPost })}>
{isEditable && (
<div className={styles.editButtons}>
<Link to={`/posts/${id}/edit`}>
<IconButton color="primary">
<EditIcon />
</IconButton>
</Link>
<IconButton onClick={onClickRemove} color="secondary">
<DeleteIcon />
</IconButton>
</div>
)}
{imageUrl && (
<img
className={clsx(styles.image, { [styles.imageFull]: isFullPost })}
src={imageUrl}
alt={title}
/>
)}
<div className={styles.wrapper}>
<div className={styles.indention}>
<h2 className={clsx(styles.title, { [styles.titleFull]: isFullPost })}>
{isFullPost ? title : <Link to={`/posts/${id}`}>{title}</Link>}
</h2>
<div className={styles.ratingprice}>
<Rating
name="size-small"
value={2.5}
size="small"
precision={0.5}
readOnly
/>
<div className={styles.review}>12 отзывов</div>
</div>
<div className={styles.price}>1150 руб.</div>
{children && <div className={styles.content}>{children}</div>}
<div className={styles.postDetails}>
<ul className={styles.postDetails}>
<li>
<EyeIcon />
<span>{viewsCount}</span>
</li>
<li>
<CommentIcon />
<span>{commentsCount}</span>
</li>
</ul>
<Button className={styles.buy} onClick={sumCount} variant="contained" endIcon={<ShoppingCartIcon fontSize="small"/>}><div className={styles.buytext}>Купить</div> </Button>
</div>
</div>
</div>
</div>
);
};

How to use params.(key) to get specific data for each route?

I want to build a car list app that will show a list of cars, and when I click on a car's details button, it will route it to another component/page that will show the details of cars.
I can get the key (vin for me) but I want to get the details of the car for each key(vin) on this page.It's like http://localhost:3000/cars/WAUZZZ4G6FN052847= key. So when a car's key will show up, all details will come due to their key number. Thank you.
index.html
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { BrowserRouter, Routes, Route, Outlet, } from "react-router-dom";
import DummyComponent from "./components/DummyComponent";
import CarDetails from "./pages/CarDetails";
import { Home } from "#mui/icons-material";
import Cars from "./pages/Cars";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<BrowserRouter>
<Routes>
<Route path="/" element={<App />} />
<Route path="/cars" element={<Outlet />} >
<Route path="list" element={<Cars />} />
<Route path=":vin" element={<CarDetails />} />
</Route>
<Route path="Home" element={<Home />} />
<Route path="DummyComponent" element={<DummyComponent />} />
</Routes>
</BrowserRouter>
);
Cars.js
import axios from "axios";
import React, { useEffect, useState } from "react";
import List from '#mui/material/List';
import ListItem from '#mui/material/ListItem';
import ListItemButton from '#mui/material/ListItemButton';
import ListItemText from '#mui/material/ListItemText';
import { Link } from "react-router-dom";
const App = () => {
const [cars, setCars] = useState([])
const getCarData = async () => {
try {
const data = await axios.get("https://react-challenge-api.azurewebsites.net/vehicles")
setCars(data.data)
}
catch (e) {
console.log(e)
}
}
useEffect(() => {
getCarData()
}, [])
return (
<div className="App">
<List sx={{ width: '100%', maxWidth: 600, bgcolor: 'background.paper' }}>
{cars.map((car) => (
<ListItemButton key={car.vin}>
<ListItem
key={car.vin}
disableGutters
secondaryAction={
<ListItemButton >
<Link to={`/cars/${car.vin}`}>details</Link>
</ListItemButton>
}
>
<ListItemText key={car.vin} primary={car.model_variant} />
</ListItem>
</ListItemButton>
))
}
</List >
</div >
);
};
export default App;
CarDetails.js (I want to show each data in this component, I used params but I don't know how to get data due to params.
import { useParams } from "react-router-dom";
const CarDetails = () => {
let params = useParams();
return (
<>
<h1>car</h1>
<ul>
this is your {params.vin}
</ul>
</>
)
}
export default CarDetails;
I would suggest moving the car data fetching into a layout route and pass the cars state down in an Outlet context.
Example:
Cars - Handles fetching the car data and passes the cars state along to nested routes via the Outlet component's context.
const Cars = () => {
const [cars, setCars] = useState([]);
const getCarData = async () => {
try {
const data = await axios.get(
"https://react-challenge-api.azurewebsites.net/vehicles"
);
setCars(data.data);
} catch (e) {
console.log(e);
}
};
useEffect(() => {
getCarData();
}, []);
return <Outlet context={{ cars }} />;
};
CarList - Reads the cars state from the Outlet context and renders the list.
const CarList = () => {
const { cars } = useOutletContext();
return (
<List sx={{ width: "100%", maxWidth: 600, bgcolor: "background.paper" }}>
{cars.map((car) => (
<ListItemButton key={car.vin}>
<ListItem
key={car.vin}
disableGutters
secondaryAction={
<ListItemButton>
<Link to={`/cars/${car.vin}`}>details</Link>
</ListItemButton>
}
>
<ListItemText key={car.vin} primary={car.model_variant} />
</ListItem>
</ListItemButton>
))}
</List>
);
};
CarDetails - Takes the vin route path param and the cars array from the outlet context and searches for a matching car object.
const CarDetails = () => {
const { vin } = useParams();
const { cars } = useOutletContext();
const car = cars.find((car) => car.vin === vin);
if (!car) {
return "No car matches this VIN";
}
return (
<>
<h1>{car.model_variant}</h1>
<ul>
<li>Body: {car.body_type}</li>
<li>Doors: {car.doors}</li>
<li>Fuel: {car.fuel_type}</li>
<li>VIN: {car.vin}</li>
<li>Registration #: {car.regno}</li>
<li>Transmission: {car.transmission_type}</li>
</ul>
</>
);
};
Routes
<Routes>
<Route path="/" element={<App />} />
<Route path="/cars" element={<Cars />}> // <-- layout route renders outlet
<Route path="list" element={<CarList />} />
<Route path=":vin" element={<CarDetails />} />
</Route>
<Route path="Home" element={<Home />} />
<Route path="DummyComponent" element={<DummyComponent />} />
</Routes>

How to change Title color when API data is active in React

I am working with a few APIs that report incidents, I have a collapse component with the titles of each upstream provider. If there's an active incident either based on an incident in the past 24 hours, or if it's in the active section, I would like to make the text in the collapse title red, otherwise make it green.
I created a new state variable called isActive, How would I go about this is React? The first is (App.js file and then Panels.js below.)
import React, { useEffect, useState } from "react";
import { Panels } from "./components/Panels";
import { BrowserRouter as Router, Routes, Route } from
"react-router-dom";
import Navbar from "./components/Navbar";
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
import Home from "./pages/Home";
import Team from "./pages/Team";
import Outages from "./pages/Outages";
function App() {
const emptyFeed = {
title: "",
link: "",
updated: "",
};
const [feed, setFeed] = useState(emptyFeed);
const [feedol, setFeedol] = useState(emptyFeed );
const [jsonData, setJsonData] = useState(emptyFeed);
const [azureData, setAzureData] = useState(emptyFeed);
const [isActive, setIsActive] = useState("false");
const getFeed = () => {
fetch("/feed")
.then((response) => response.json())
.then((data) => {
setFeed(data);
});
};
const getFeedOl = () => {
fetch("/feed_ol")
.then((response) => response.json())
.then((data) => {
setFeedol(data);
});
};
const getJsonData = () => {
fetch("/json_data")
.then((response) => response.json())
.then((data) => {
setJsonData(data["archive"][0]);
});
};
const getAzureData = () => {
fetch("/azure_data")
.then((response) => response.json())
.then((data) => {
setAzureData(data);
});
};
const getAllFour = () => {
getFeed();
getFeedOl();
getJsonData();
getAzureData();
};
useEffect(() => {
getAllFour();
}, []);
return (
<>
<Router>
<Navbar />
<Routes>
<Route exact path="/" element={<Home />} />
<Route path="/team" element={<Team />} />
<Route path="/outages" element={<Outages />} />
</Routes>
</Router>
<Panels
feed={feed}
feedol={feedol}
jsonData={jsonData}
azureData={azureData}
getAllFour={getAllFour}
/>
</>
);
}
export default App;
import React from "react";
import { Collapse } from "antd";
import { Card, Container } from "react-bootstrap";
import { BsArrowClockwise } from "react-icons/bs";
import "./panels.css";
import "antd/dist/antd.css";
const { Panel } = Collapse;
export const Panels = ({ feed, feedol, jsonData,
azureData,
getAllFour }) => {
return (
<Container>
<Card className="table-card">
<Card.Header>
{" "}
<button
type="button"
className=" refresh-button"
onClick={getAllFour}
>
{" "}
<BsArrowClockwise />
</button>{" "}
Upstream Outages{" "}
</Card.Header>
<Collapse accordion>
<Panel header={feedol.title} key="1">
<p>{}</p>
</Panel>
<Panel header={feed.title} key="2">
<p>{}</p>
</Panel>
<Panel header={azureData.title} key="3">
<p>{}</p>
</Panel>
<Panel header={jsonData.service_name} key="4">
<p>{}</p>
</Panel>
</Collapse>
</Card>
</Container>
);
};

How to pass location state and URL params using React-Router?

When I click on the link in the HoverBooks Component to get to a new page where I can render the book location state in Book component, but when I press on it nothing happens. I think the error is in Route:
function App() {
return (
<div className="App">
<Router>
<Switch>
<Route path="/book:/book.Key">
<Book />
</Route>
<Route path="/signin">
<Signin />
</Route>
<Route path="/">
<Header />
<Home />
</Route>
</Switch>
</Router>
</div>
)
}
export default App
import React from 'react'
import { useLocation } from 'react-router-dom'
const Book = () => {
const {
state: { book },
} = useLocation()
console.log({ book })
return (
<div key={book.key}>
<h1>{book.bookName}</h1>
</div>
)
}
export default Book
const HoverBooks = ({ ...book }) => {
const [inHoverBooks, setInHoverBooks] = React.useState(false)
return (
<>
<Link
to={{
pathName: `/book/${book.key}`,
state: {
book,
},
}}
>
<img
onMouseLeave={() => setInHoverBooks(false)}
onMouseEnter={() => setInHoverBooks(true)}
src={book.image}
key={book.key}
/>
</Link>
{inHoverBooks && (
<div className="hover__containter">
<h3>{book.bookName}</h3>
<h2>{book.by}</h2>
<h2>{book.Narreted}</h2>
<h2>{book.length}</h2>
<h2>{book.rating}</h2>
</div>
)}
</>
)
}
export default HoverBooks
Below is the correct form, e.g. /:someName, to define a route with URL params:
<Route path="/book/:bookKey">
<Book />
</Route>
And here is the right syntax to make a Link for the above route:
<Link
to={{
pathname: `/book/SOME_BOOK_KEY`, // replace SOME_BOOK_KEY with some value
state: {
book, // e.g. const book = { key: 'js', bookName: 'Learn JavaScript'}
},
}}
>
<img src="some_src" alt="something" />
</Link>
And you useParams and useLocation react-hooks to access the "URL params" and "location state" in a component:
const Book = () => {
const {
state: { book },
} = useLocation()
const { bookKey } = useParams();
console.log(book, bookKey)
// prints "book" object (from location state) and "bookKey" (from URL params)
return (
<div key={book.key}>
<h1>{book.bookName}</h1>
</div>
)
}
I would suggest you to add typescript to your ReactJS app. It helps you find errors early by doing "static Type-checking".
With react router you need to pass the component you want to render to the Route like this
const ComponentA = (props) => {...}
<Route path="/component-a" component={ComponentA} />
And here is how to link to component a
<Link to="/component-a" >Go to component A</Link>

how to use individual component from an API by calling dynamically in React?

I implement a project where i have to call API. From this API enter link description here first i show 250 countries and then create a details component where show all details individually by clicking a button or link. But i faced some problem. Since i have a little knowledge about react and API so i didn't understand how to call API for individually show country details in my details component. I need help because i want to know that how can I dynamically call single country from 250 countries API
----------This is the component here i load all countries by calling rest API. After that i couldn't call any single country
This is my country details component where i want to load individual country details
After getting some help i understand that api is coming in useState but i can not implement
import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
const CountryDetails = () => {
const {countryName} = useParams();
const [country,setCountry] = useState([]); //use object
console.log(countryName);
console.log(country[0]);
useEffect(()=>{
// const url = `https://restcountries.eu/rest/v2/all`;
const url = `https://restcountries.eu/rest/v2/name/${countryName}`;
fetch(url)
.then(res => res.json())
.then(data => setCountry(data));
},[countryName])
// console.log(country);
return (
<div>
<h3>This is {countryName}</h3>
{/* <h2>{country[0]}</h2> */}
<h4>{countryName.capital}</h4>
</div>
); }; export default CountryDetails;
this is App.js in my project
import './App.css';
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useParams,
useRouteMatch
} from "react-router-dom";
import Home from './Components/Home/Home';
import CountryDetails from './Components/CountryDetails/CountryDetails';
import NotFound from './Components/NotFound/NotFound';
function App() {
return (
<Router>
<Switch>
<Route path="/home">
<Home/>
</Route>
<Route path="/:countryName">
<CountryDetails></CountryDetails>
</Route>
<Route exact path="/">
<Home />
</Route>
<Route path="*">
<NotFound></NotFound>
</Route>
</Switch>
</Router>
);
} export default App;
I need to implement this component for showing individual country details
I think the issue is with how you attempt to render the details. The country data will still be in array format. countryName is the string route parameter, so it won't have any country specific properties to call.
<div>
<h3>This is {countryName}</h3>
{/* <h2>{country[0]}</h2> */}
<h4>{countryName.capital}</h4> // <-- countryName is string!!
</div>
You can simply map the country results similarly to how it was done on the main page. Destructure the detail values you want to use for rendering the details.
return country.map(({ capital, name }) => ( // <-- destructure all values needed
<div key={name} className="country">
<h3>
Country Name: {name}
</h3>
<div>
Capital: {capital}
</div>
<button type="button" onClick={history.goBack}>Back</button>
</div>
))
Full Demo Code:
Home page
const Home = () => {
const [countries, setCountries] = React.useState([]);
React.useEffect(() => {
fetch("https://restcountries.eu/rest/v2/all")
.then((res) => res.json())
.then((data) => setCountries(data));
}, []);
const history = useHistory();
return countries.map(({ capital, name }) => (
<div key={name} className="country">
<div>Country Name: {name}</div>
<div>Capital: {capital}</div>
<button
type="button"
onClick={() =>
history.push({
pathname: `/${name}`
})
}
>
Details
</button>
</div>
));
};
Details page
const CountryDetails = () => {
const { countryName } = useParams();
const [country, setCountry] = React.useState([]);
React.useEffect(() => {
fetch(`https://restcountries.eu/rest/v2/name/${countryName}`)
.then((res) => res.json())
.then((data) => setCountry(data));
}, [countryName]);
const history = useHistory();
return country.map(
({ capital, flag, name, nativeName, population, region, subregion }) => (
<div key={name} className="country">
<h3>Country Name: {name}</h3>
<img
src={flag}
alt="flag"
style={{
height: "100px"
}}
/>
<div>Capital: {capital}</div>
<div>Region: {region}</div>
<div>Subregion: {subregion}</div>
<div>Population: {population}</div>
<div>Native Name: {nativeName}</div>
<button type="button" onClick={history.goBack}>
Back
</button>
</div>
)
);
};
App
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<Router>
<Switch>
<Route path="/:countryName">
<CountryDetails />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</Router>
</div>
);
}
You are making a mistake when accessing the data in CountryDetails component.
Instead of this
<h4>{countryName.capital}</h4>
Do this
<h4>{country[0].capital}</h4>

Categories

Resources