Having trouble displaying a list of Github usernames and profile pics.
I'm using https://api.github.com/users to fetch the data from the API. I haven't started working on the profile links yet.
Here's what's being displayed
Here's my App.js:
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'
import Home from './pages/Home';
import About from './pages/About';
import NotFound from './pages/NotFound';
import Navbar from './components/layout/Navbar';
import Footer from './components/layout/Footer';
function App() {
return (
<Router>
<div className='flex flex-col justify-between h-screen'>
<Navbar />
<main className='container mx-auto px-3 pb-12'>
<Routes>
<Route path='/' element={< Home />} />
<Route path='/about' element={< About />} />
<Route path='/notfound' element={< NotFound />} />
<Route path='/*' element={< NotFound />} />
</Routes>
</main>
<Footer />
</div>
</Router>
);
}
export default App;
Here's UserResults.jsx:
import {useEffect, useState} from 'react'
import Spinner from '../layout/Spinner'
import UserItem from './UserItem'
function UserResults() {
const [users, setUsers] = useState([])
const [loading, setLoading] = useState(true)
useEffect(() => {
fetchUsers()
}, [users])
const fetchUsers = async () => {
const response = await fetch(`https://api.github.com/users`)
const data = await response.json()
setUsers(data)
setLoading(false)
}
if (!loading) {
return (
<div className='grid grid-cols-1 gap-8 xl:grid-cols-4
lg:grid-cols-3 md:grid-cols-2'>
{users.map((user) => (
<UserItem key={user.id} user={user} />
))}
</div>
)
} else {
return <h3><Spinner /></h3>
}
}
export default UserResults
UserItem.jsx which displays the user info:
import { Link } from 'react-router-dom'
import PropTypes from 'prop-types'
function UserItem({users: login, avatar_url}) {
return (
<div className='card shdow-md compact bg-base-100 '>
<div className='flex-row items-center space-x-4 card-body'>
<div>
<div className='avatar'>
<div className='rounded-full shadow w-14 h-14'>
<img src={avatar_url} alt='profile pic'></img>
</div>
</div>
</div>
<div>
<h2 className='card-title'>{login}</h2>
<Link className='text-base-content text-opacity-40' to={`/users/${login}`}>
Visit Profile
</Link>
</div>
</div>
</div>
)
}
UserItem.propTypes = {
users: PropTypes.object.isRequired,
}
export default UserItem
Feel like I'm missing something with the way I reference the API.
Thank you in advance!
The UserItem component is being called as:
<UserItem key={user.id} user={user} />
You should define it as follows:
function UserItem({key, user}) {
// here you can use user.avatar_url and any other user related key
Seems that object destructuring in UserItem function is written wrong:
function UserItem({users: { login, avatar_url }}) {
Related
import React, { useEffect, useState } from 'react'
import { Link } from 'react-router-dom';
import './Allproducts.css'
import Categories from './categories.json'
import ForYouItem from './ForYouItem'
export default function Allproducts(props) {
const [products, setProducts] = useState([]);
useEffect(() => {
fetch(`https://fakestoreapi.com/products/category/${props.category}`)
.then((res) => res.json())
.then((data) => setProducts(data))
}, [])
return (
<>
<div className="banner">
<h1>All Products</h1>
<h4>Get best items in budget</h4>
</div>
<div className="main-grid">
<div className="left-grid">
<div className="left-categories">
<h1>Collections</h1>
{Categories.map((category) => {
let Afeef = `/${props.category}`
return (
<Link to= {Afeef} className='products-categories'> <h4>{category.title}</h4></Link>
)
}
)}
</div>
</div>
<div className="right-grid">
<div className="row ">
{products.map((product) => {
return (
<div className="col-md-4 my-2 Products-1">
<ForYouItem Title={product.title.slice(0, 50)} Price={product.price} Imageurl={product.image} rate={product.rating.rate} count={product.rating.count} />
</div>
)
}
)}
</div>
</div>
</div>
</>
)
}
So in this code I am calling same prop two times, first in this line;
fetch(https://fakestoreapi.com/products/category/${props.category})
Secondly here;
let Afeef = /${props.category}
The prop is working in the First line but on the second line it gives no result. The link isn't changed.
What I want is when I click on second Link I get redirected "/${props.category}" but the URL is not changing
Code for App.js:
import React, { Component } from 'react'
import './App.css';
import NavBar from './components/NavBar';
import TopBar from './components/TopBar'
import {
HashRouter,
Routes,
Route,
} from "react-router-dom";
import Mainpage from './Mainpage';
import Login from './components/Login';
import Signup from './components/Signup';
import Allproducts from './components/Allproducts';
function App() {
return (
<div>
<HashRouter>
<TopBar/>
<NavBar/>
<Routes>
<Route path="/" element={<Mainpage/>}></Route>
<Route path="/Login" element={<Login/>}></Route>
<Route path="/Signup" element={<Signup/>}></Route>
<Route path="/jewelery" element={<Allproducts category="jewelery"/>}></Route>
<Route path="/electronics" element={<Allproducts category="electronics"/>}></Route>
<Route path="/men's clothing" element={<Allproducts category="men's clothing"/>}></Route>
<Route path="/women's clothing" element={<Allproducts category="women's clothing"/>}></Route>
</Routes>
</HashRouter>
</div>
);
}
export default App;
I am testing a React/Typescript component using Jest and React Testing-Library. I am doing a simple render test and getting a Reference Error: Worker is not defined.
Why and how would I use a worker in this testing context?
Here is my simple test:
import {render, screen} from '#testing-library/react'
import userEvent from '#testing-library/user-event'
import React from 'react'
import {Router} from 'react-router-dom'
import AppRouter from '../router'
test('AppRouter renders all routes and I can navigate to those pages', () => {
render(<AppRouter />)
screen.debug()
})
And here is the AppRouter component:
import { BrowserRouter, Switch, Route, Redirect } from 'react-router-dom'
import { useState } from 'react'
import useLocalStorage from './hooks/useLocalStorage'
import * as Constants from './constants'
import Header from './layout/header/header'
import MainPage from './pages/mainPage/mainPage'
import PostPage from './pages/postPage/postPage'
import UserPage from './pages/userPage/userPage'
import LoginPage from './pages/loginPage/loginPage'
import SignupPage from './pages/signupPage/signupPage'
import NewPage from './pages/newPage/newPage'
import FeedbackPage from './pages/feedbackPage/feedbackPage'
import AdminPage from './pages/adminPage/adminPage'
import SettingPage from './pages/settingPage/settingPage'
import { WebContext } from './context/WebContext'
import Favicon from 'react-favicon'
const AppRouter = () => {
const [adminCode, setAdminCode] = useLocalStorage('admin', '')
const [isMenuOpen, setIsMenuOpen] = useState(false)
const [page, setPage] = useState(Constants.Page.Home)
return (
<BrowserRouter>
<div>
<Favicon url={require('../public/favicon.ico')} />
<WebContext.Provider
value={{
isMenuOpen,
setIsMenuOpen,
page,
setPage,
adminCode,
setAdminCode,
}}
>
<Header />
<Switch>
<Route component={MainPage} path="/" exact={true} />
<Route component={PostPage} path="/post/:id" />
<Route component={UserPage} path="/user" />
<Route component={LoginPage} path="/login" />
<Route component={SignupPage} path="/signup" />
<Route component={NewPage} path="/new" />
<Route component={FeedbackPage} path="/feedback" />
<Route component={AdminPage} path="/admin" />
<Route component={SettingPage} path="/setting" />
<Route component={() => <Redirect to="/" />} />
</Switch>
</WebContext.Provider>
</div>
</BrowserRouter>
)
}
export default AppRouter
Most of what I researched on this were old Jest stackoverflows. I am aware there is a jest-worker package but not sure why I would need this or how I would use it when running this simple test.
Here is a link to jest-worker.
Code Trace:
Header component
import { useContext, useState } from 'react'
import { NavLink, useHistory, useLocation } from 'react-router-dom'
import { observer } from 'mobx-react-lite'
import { WebContext } from '../../context/WebContext'
import UnirepContext from '../../context/Unirep'
import UserContext from '../../context/User'
const Header = () => {
const history = useHistory()
const location = useLocation()
const { isMenuOpen, setIsMenuOpen } = useContext(WebContext)
const [searchInput, setSearchInput] = useState<string>('')
const unirepConfig = useContext(UnirepContext)
const userContext = useContext(UserContext)
const gotoNewPage = () => {
if (
userContext.userState &&
userContext.netReputation >= unirepConfig.postReputation
) {
history.push(`/new`, { isConfirmed: true })
}
}
const gotoUserPage = () => {
history.push(`/user`, { isConfirmed: true })
}
const openMenu = () => {
if (!isMenuOpen) {
console.log('open menu!')
setIsMenuOpen(true)
}
}
const handleSearchInput = (event: any) => {
console.log('search input : ' + event.target.value)
}
return (
<header>
<div className="navLinks">
<NavLink to="/" className="link" activeClassName="active" exact>
<img
src={require('../../../public/images/unirep-title.svg')}
/>
</NavLink>
</div>
{/* <div className="search-bar">
<div className="search-icon"><FaSearch /></div>
<form>
<input type="text" name="searchInput" placeholder="Search by keyword, user names or epoch key" onChange={handleSearchInput} />
</form>
</div> */}
{userContext.userState ? (
<div className="navButtons">
<div id="rep" onClick={gotoUserPage}>
<img
src={require('../../../public/images/lighting.svg')}
/>
{userContext.netReputation}
</div>
<div
id="new"
className={
location.pathname === '/new'
? 'navBtn chosen'
: 'navBtn'
}
>
<img
src={require('../../../public/images/newpost.svg')}
onClick={gotoNewPage}
/>
</div>
<div
id="user"
className={
location.pathname === '/user'
? 'navBtn chosen'
: 'navBtn'
}
>
<img
src={require('../../../public/images/user.svg')}
onClick={gotoUserPage}
/>
</div>
<div className="navBtn">
<img
src={require('../../../public/images/menu.svg')}
onClick={openMenu}
/>
</div>
</div>
) : (
<div className="navButtons">
<div
id="login"
className="whiteButton"
onClick={() => history.push('/login')}
>
Sign in
</div>
<div
id="join"
className="blackButton"
onClick={() => history.push('/signup')}
>
Join
</div>
<div id="menu" className="navBtn">
<img
src={require('../../../public/images/menu.svg')}
onClick={openMenu}
/>
</div>
</div>
)}
</header>
)
}
export default observer(Header)
EDIT
The problem may stem from using MobX for state management and not wrapping the component in a Provider but still unsure of how to do this.
I have a problem with my proxy. When I am in the homepage, the proxy is working but when I go to another page (using Link from react-router-dom) it's not taken into account.
I have the error: Object { message: "Request failed with status code 404", name: "AxiosError", code: "ERR_BAD_REQUEST"..}
and the http request is : http://localhost:3000/profile/posts/profile/olive
but I want it to be : http://localhost:8800/api/profile/olive
In package.json I have : "proxy": "http://localhost:8800/api/"
And here are the scripts that I use (Feed.jsx):
import "./feed.css";
import Share from "../share/Share";
import Post from "../post/Post";
import { useState, useEffect } from "react";
import axios from "axios"
export default function Feed({ username }) {
const [posts, setPosts] = useState([]);
useEffect(() => {
const fetchPosts = async () => {
const res = username
? await axios.get("posts/profile/" + username)
: await axios.get("posts/timeline/629f61ef4ed27a5d39094ced");
setPosts(res.data)
};
fetchPosts();
}, []);
return (
<div className="feed">
<div className="feedWrapper">
<Share />
{posts.map((p) => (
<Post key={p._id} post={p} />
))}
</div>
</div>
)}
This is my App.js:
import {
BrowserRouter as Router,
Routes as Switch,
Route,
} from "react-router-dom";
import Homepage from "./pages/homepage/Homepage";
import Login from "./pages/login/Login"
import Register from "./pages/register/Register"
import Profile from "./pages/profile/Profile"
function App() {
return (
<>
<Router>
<Switch>
<Route exact path="/" element={<Homepage/> }/>
<Route exact path="/login" element={<Login/> }/>
<Route exact path="/register" element={<Register/> }/>
<Route path="/profile/:username" element={<Profile/> }/>
</Switch>
</Router>
</>
);
}
export default App;
This is my Profile.jsx:
import "./profile.css"
import Topbar from "../../components/topbar/Topbar";
import Sidebar from "../../components/sidebar/Sidebar";
import Feed from "../../components/feed/Feed";
import Rightbar from "../../components/rightbar/Rightbar";
export default function Profile() {
const PF=process.env.REACT_APP_PUBLIC_FOLDER;
return(
<>
<Topbar/>
<div className="profile">
<Sidebar/>
<div className="profileRight">
<div className="profileRightTop">
<div className="profileCover">
<img src={`${PF}post/3.jpeg`} alt="" className="profileCoverImage" />
<img src={`${PF}person/5.jpeg`} alt="" className="profileUserImage" />
</div>
<div className="profileInfo">
<h4 className="profileInfoName">Louise Dupuis</h4>
<span className="profileInfoDesc">Hello everyone I am a spiritual coach</span>
</div>
</div>
<div className="profileRightBottom">
<Feed username="olive"/>
<Rightbar profile/>
</div>
</div>
</div>
</>
);
}
And this is how I linked a button from the homepage to the profile page.
<Link to={`/profile/${user.username}`}>
<img className="postProfileImage" src={user.profilePicture || PF+"person/no_avatar.png"} alt="" />
</Link>
Thank you in advance for your attention and your help. I really tried and searched but I didn't find. I don't know what's wrong in my code ...
This is the content of my App.jsx. Note when I remove the React router piece and add the PDPContent component directly within JSX It renders just fine.
import React, { Suspense, useState } from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import PDPContent from "./PDPContent";
import "./index.scss";
const Header = React.lazy(() => import("home/Header"));
const Footer = React.lazy(() => import("home/Footer"));
import SafeComponent from "./SafeComponent";
const App = () => (
<Router>
<div className="text-3xl mx-auto max-w-6xl">
<SafeComponent>
<Suspense fallback={<div>Loading</div>}>
<Header />
</Suspense>
</SafeComponent>
<div className="my-10">
<Switch>
<Route path="/product/:id" component={PDPContent} />
</Switch>
</div>
<Suspense fallback={<div>Loading</div>}>
<Footer />
</Suspense>
</div>
</Router>
);
ReactDOM.render(<App />, document.getElementById("app"));
This is the content of my PDPContent.jsx. Note when I remove useParams below and hard code the value of the product id as 10, it works just fine.
import React, { useState, useEffect } from "react";
import { getProductById, currency } from "home/products";
import { useParams } from "react-router-dom";
export default function PDPContent() {
const { id } = useParams();
const [product, setProduct] = useState(null);
useEffect(() => {
if (id) {
getProductById(id).then((product) => {
setProduct(product);
});
} else {
setProduct(null);
}
}, [id]);
console.log("Id is ");
console.log(id);
if (!product) return null;
return (
<div className="grid grid-cols-2 gap-5">
<div>
<img src={product.image} alt={product.name} />
</div>
<div>
<div className="flex">
<h1 className="font-bold text-3xl flex-grow">{product.name}</h1>
<div className="font-bold text-3xl flex-end">
{currency.format(product.price)}
</div>
</div>
<div className="mt-10">{product.description}</div>
<div className="mt-10">{product.longDescription}</div>
</div>
</div>
);
}
I have this program where Product.js just showing a list of items with an addToCart button. In the Cart.js, I am trying to show just the items I selected. Following are the files:
App.js
import './App.css';
import React,{useState} from 'react';
import {
Route,
BrowserRouter as Router,
Switch,
} from 'react-router-dom';
import Cart from './components/Cart';
import Product from './components/Product';
import {ProductProvider} from './ItemListContext';
function App() {
const [cart, setCart]= useState([]);
const addToCart=(product)=>{
setCart([...cart, {...product}])
}
console.log(cart)
return (
<div className="App">
<ProductProvider>
<Router>
<Switch>
<Route path="/" exact
render ={()=> < Product addToCart={addToCart}/>}
/>
<Route path="/cart/" exact
render ={()=> < Cart cart = {cart} />}
/>
</Switch>
</Router>
</ProductProvider>
</div>
);
}
export default App;
Product.js
import React,{useContext, useState} from 'react';
import {ProductContext} from '../ItemListContext';
export default function Product({addToCart}) {
const [products, setProducts] = useContext(ProductContext)
return(
<div className="main-page">
products
<h1>Product Page </h1>
<div className="products" >
{products.map((product, idx)=>(
<div key={idx}>
<h3>{product.name} </h3>
<img src= {product.image} /> cost = {product.cost}
<button onClick={()=>addToCart(product)}
>Add to Cart</button>
</div>
))}
</div>
<div>
</div>
</div>
)
}
ItemListContext.js
import React,{createContext, useState} from 'react';
export const ProductContext = createContext();
export function ProductProvider(props) {
const [products, setProducts]=useState([
{
name: 'iPhone',
cost : '$899.99',
image: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQB6BMWrPXA9KyTtxa6o600mjeUNJ7zSXgaNt--FDCR6YjQ4XWS5G1J3dSF5ChurfQEGxorkxYs&usqp=CAc',
},
{
name: 'Samsung',
cost : '$599.99',
image: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQUGMCcF3_XBIKH5Dja-9iCkRP4CSA-CYaylQ&usqp=CAU'
}
])
return (
<div>
<ProductContext.Provider value={[products, setProducts]} >
{props.children}
</ProductContext.Provider>
</div>
)
}
Cart.jsx
import React from 'react';
export default function Cart({cart}) {
console.log()
return (
<div className="cart">
<h1>cart {cart.length}</h1>
<div className="products" >
{cart.map((product, idx)=>(
<div key={idx}>
<h3>{product.name}</h3>
<h4>{product.cost}</h4>
<img src={product.image} alt = {product.name} />
</div>
))}
</div>
<div>
</div>
</div>
)
}
I am trying to create the router link, localhost:3000/ is showing the product list, but localhost:3000/cart/ doesn't show the cart items.
However, if I remove the Routers and run the program like this:
App.js
import './App.css';
import React,{useState} from 'react';
import {
Route,
BrowserRouter as Router,
Switch,
} from 'react-router-dom';
import Cart from './components/Cart';
import Product from './components/Product';
import {ProductProvider} from './ItemListContext';
function App() {
const [cart, setCart]= useState([]);
const addToCart=(product)=>{
setCart([...cart, {...product}])
}
console.log(cart)
return (
<div className="App">
<ProductProvider>
< Product addToCart={addToCart}/>
<Cart cart={cart} />
</ProductProvider>
</div>
);
}
export default App;
the program works just fine.
So my question is, am I doing my Routing the right way? Is this the right way to pass the cart prop?
There are no problem with Routing, you can add the Link above that and it works as expected https://codesandbox.io/s/solitary-river-hvv2q
...
<ProductProvider>
<Router>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/cart">Cart</Link>
</li>
</ul>
<Switch>
<Route path="/" exact>
<Product addToCart={addToCart} />
</Route>
<Route path="/cart/" exact>
<Cart cart={cart} />
</Route>
</Switch>
</Router>
</ProductProvider>
...
When you directly navigate to /cart by typing that link on browser, your App is re-render then cart is set to empty array, you should store it in storage to prevent that issue.