API data not printing but successes with console.log - reactjs

I'm trying to learn about APIs and trying to code a REACT app to go along with it. I am sure the issue is a minor one, but I can't seem to crack it.
The relevant code is pasted below, the API is fetched in index.js.
The contents of the API is printed to the console without issue but I can not seem to get it right when going through my list and event details.
I am new to coding so I would appreciate any feedback given.
App.js
import React, { useState, useEffect } from "react";
import { CssBaseline, Grid } from "#material-ui/core";
import { getEventsData } from "./api";
import Header from "./components/Header/Header";
import List from "./components/List/List";
import EventDetails from "./components/EventDetails/EventDetails";
const App = () => {
const [events, setEvents] = useState([]);
useEffect(() => {
getEventsData()
.then((data) => {
console.log(data);
console.log(Array.isArray(data))
setEvents(data);
})
}, []);
return (
<>
<CssBaseline />
<Header />
<List EventDetails={EventDetails} />
</>
)
}
export default App;
index.js
import axios from "axios";
const URL = 'https://api-football-v1.p.rapidapi.com/v3/fixtures'
const options = {
params: {date: '2022-02-12', league: '39', season: '2021'},
headers: {
'x-rapidapi-host': 'api-football-v1.p.rapidapi.com',
'x-rapidapi-key': xxxXXXxxxXXXxxx'
}
};
export const getEventsData = async () => {
try {
const { data } = await axios.get(URL, options);
// Kan det ha något med options att göra? https://stackoverflow.com/questions/68367352/multiple-url-variable-async-await-axios
return data;
} catch (error) {
}
};
List.jsx
import React, { useState } from "react";
import { CircularProgress, Grid, Typography, InputLabel, MenuItem, FormControl, Select, ButtonGroup, Button } from "#material-ui/core";
import EventDetails from "../EventDetails/EventDetails"
import useStyles from "./styles"
const List = ({ events }) => {
const classes = useStyles();
const [type, setType] = useState("premierleague");
return (
<div className={classes.container}>
<FormControl className={classes.formControl}>
<InputLabel>Sport</InputLabel>
<Select value={type} onChange={(e) => setType(e.target.value)}>
<MenuItem value="premierleague">Premier League</MenuItem>
<MenuItem value="formula1">Formula 1</MenuItem>
</Select>
{/*<ButtonGroup value={type} onClick={(e) => setType(e.target.value)}>
<Button value="premierleague">Premier League</Button>
<Button value="formula1">Formula 1</Button>
</ButtonGroup>*/}
</FormControl>
<Grid container spacing={3} className={classes.list}>
{events?.map((event, i) => (
<Grid item key={i} xs={12}>
<EventDetails event={event} />
</Grid>
))}
</Grid>
</div>
)
}
export default List;
EventDetails.jsx
import React from "react";
const EventDetails = ({ event }) => {
console.log(event)
return (
<h3>{event.league}</h3>
)
}
export default EventDetails;

You're not sending the events to List component.
Try changing in App.js:
return (
<>
<CssBaseline />
<Header />
<List events={events} />
</>
)

Related

Badge on Cart not updating itself unless I refresh the Page

App.js Code
import React, { useState, useEffect } from 'react';
import Products from './components/Products/Products';
import Navbar from './components/Navbar/Navbar';
import { commerce } from './lib/commerce';
const App = () => {
const [products, setProducts] = useState([]);
const [cart, setCart] = useState({});
const fetchProducts = async () => {
const { data } = await commerce.products.list();
setProducts(data);
};
const fetchCart = async () => {
setCart(await commerce.cart.retrieve());
};
const handleAddToCart = async (productId, quantity) => {
const item = await commerce.cart.add(productId, quantity);
setCart(item.cart);
};
useEffect(() => {
fetchProducts();
fetchCart();
}, []);
commerce.cart.empty();
console.log(cart);
return (
<div>
<Navbar totalItems={cart.total_items} />
<Products products={products} onAddToCart={handleAddToCart} />
</div>
);
}
export default App;
NavBar.js
import React from 'react'
import { AppBar, Typography, Toolbar, IconButton, Badge, Menu, MenuItem } from '#material-ui/core'
import { ShoppingCart } from '#material-ui/icons'
import useStyles from './styles'
const Navbar = ({ totalItems }) => {
const classes = useStyles();
return (
<>
<AppBar position='fixed' className={classes.appBar} color='inherit' >
<Toolbar>
{/* THIS WILL BE ON LEFT */}
<Typography variant='h6' color='inherit' className={classes.title}>
<img src="https://image.shutterstock.com/image-photo/image-260nw-611143775.jpg" alt="e-commerce" className={classes.image} height="25px" />
E-store
</Typography>
{/* THIS IS USE TO TAKE AS MUCH SPACE AS WE WANT INORDER TO SEPERTE LEFT AND RIGHT */}
<div className={classes.grow} />
{/* FOR RIGHT PART */}
<div className={classes.button}>
<IconButton aria-label='Show Items' color='inherit'>
<Badge overlap="rectangular" badgeContent={totalItems} color='secondary'>
<ShoppingCart />
</Badge>
</IconButton>
</div>
</Toolbar>
</AppBar>
</>
)``
}
export default Navbar
**commerce.js**
import Commerce from "#chec/commerce.js";
export const commerce = new Commerce(
"HERE_MY_API_KEY"
);
I am getting an error: "Cannot read properties of undefined (reading 'total_items')" but everything looks good on refreshing. On clicking the button the error occurs but after refreshing, the error is gone and I can see my result.
The main problem is that I need to refresh the page. this problem also arises when I add items to the cart. The items get added but are not shown in the console.
Edit: I edited my post to add the whole APP.js component.
import React, { useState, useEffect } from 'react';
import Products from './components/Products/Products';
import Navbar from './components/Navbar/Navbar';
import { commerce } from './lib/commerce';
const App = () => {
const [products, setProducts] = useState([]);
const [cart, setCart] = useState({});
const fetchProducts = async () => {
const { data } = await commerce.products.list();
setProducts(data);
};
const fetchCart = async () => {
const cartItems = await commerce.cart.retrieve();
setCart(cartItems);
};
const handleAddToCart = async (productId, quantity) => {
const item = await commerce.cart.add(productId, quantity);
// I am not sure how your cart object is structured
// but you should add the new item (item.cart)
// to the existing elements.
setCart((cartItems) => [...cartItems, item.cart]);
};
useEffect(() => {
fetchProducts();
fetchCart();
}, []);
useEffect(() => {
console.log(cart);
}, [cart]);
// I don't know why you empty your cart.
// explain in the comments and I'll change it if need be
// commerce.cart.empty();
return (
<div>
{products.length>0 && cart && cart?.total_items && (
<>
<Navbar totalItems={cart.total_items} />
<Products products = {products} onAddToCart=
{handleAddToCart} />
</>
)}
</div>
);
}
export default App;

in NEXTJS Warning: Expected server HTML to contain a matching <div> in <div>

I am using nextjs and mui. I am facing a warning when rendering pages. Here is my code. Please help to solve the issue!!!
import "../styles/globals.scss";
import { AppProps } from "next/app";
import useGetAuthentication from "../hooks/useGetAuthentication";
import States from "../interfaces/states";
import STATUS from "../constants/status";
import { CssBaseline } from "#mui/material";
import { ThemeProvider } from "#mui/material/styles";
import theme from "../styles/theme";
import Layout from "../layouts/Layout";
import Head from "next/head";
import * as React from "react";
import Login from "../components/Login";
import { Box } from "#mui/material";
interface MyAppProps extends AppProps {
emotionCache?: EmotionCache;
}
const checkStatusCode = (statusCode: number): boolean => {
return statusCode === STATUS.NOT_FOUND || statusCode === STATUS.INTERNAL_SERVER_ERROR;
};
function App({ Component, pageProps }: AppProps) {
const { states } = pageProps;
const { statusCode } = pageProps;
const { isAuthorized } = useGetAuthentication(states as States);
console.log("App -> Component", Component);
console.log("App -> pageProps", pageProps);
console.log("App -> states", states);
console.log("App -> statusCode", statusCode);
const drawerWidth: number = 240;
if (!checkStatusCode(statusCode) && !isAuthorized)
return (
<Box
component="main"
sx={{
flexGrow: 1,
p: 3,
width: { lg: "230px", sm: `calc(100% - ${drawerWidth}px)` }
}}
>
<Login />
</Box>
);
return (
<>
<Head>
<meta name="viewport" content="initial-scale=1, width=device-width" />
</Head>
<ThemeProvider theme={theme}>
<CssBaseline />
<Layout>
<Component {...pageProps} />
</Layout>
</ThemeProvider>
</>
);
}
export default App;
Login component is below
import React, { useEffect } from "react";
import authenticationStore from "../../stores/persistences/authenticationStore";
import TestHttp from "../../httpModules/testHttp";
import STATUS from "../../constants/status";
import RequestSignIn from "../../interfaces/test/requestSignIn";
import styles from "./login.module.scss";
import { Alert, FormControlLabel, Grid, Paper, TextField, Typography, Stack, Button, Checkbox } from "#mui/material";
import Image from "next/image";
import useLoginInputs from "../../hooks/useLoginInputs";
import LocalStorageHandler from "../../utils/localStorageHandler";
import RememberId from "../../interfaces/rememberId";
import ERROR_MESSAGE from "../../constants/errorMessage";
import LOGIN_INFO from "../../constants/loginInfo";
const Login: React.FC = () => {
const localStorageHandler = new LocalStorageHandler<RememberId>();
const authorize = authenticationStore((state) => state.authorize);
const testHttp = new TestHttp();
const { inputs, setInputs, isRememberChecked, isError, setIsError, isIdEmpty, setIsIdEmpty, isPasswordEmpty, setIsPasswordEmpty, inputsHandler, checkboxHandler } = useLoginInputs([
"id",
"password"
]);
const { id, password } = inputs;
const onLoginHandler = async (): Promise<void> => {
if (isIdEmpty) {
return setIsError(ERROR_MESSAGE.ID_EMPTY);
}
if (isPasswordEmpty) {
return setIsError(ERROR_MESSAGE.PASSWORD_EMPTY);
}
const signInInfo: RequestSignIn = { id, password };
const { statusCode, jsonResult } = await testHttp.signIn(false, signInInfo);
/*
* 인증 실패 (아이디, 비밀번호 일치 하지 않는 경우 등) 발생 시 코드 작성
*/
if (statusCode !== STATUS.OK) {
setIsError(true);
return;
}
const { userInfo, tokenInfo } = jsonResult;
authorize(statusCode, userInfo, tokenInfo);
if (!isRememberChecked) return localStorageHandler.removeLocalStorageData(LOGIN_INFO.REMEMBER_ID);
localStorageHandler.setLocalStorageData("rememberId", {
id
});
};
useEffect(() => {
console.log("하이");
setIsIdEmpty(id.length <= 0);
setIsPasswordEmpty(password.length <= 0);
setIsError(null);
}, [id, password]);
console.log("id", id);
console.log("password", password);
return (
<Grid>
<Paper elevation={10} className={styles.container}>
<Grid align={"center"}>
<div className={styles.logo}>
<Image src={"/images/logo.svg"} width={"200px"} height={"80px"} alt={"logo"} />
<Typography variant={"h6"}>관리자</Typography>
</div>
</Grid>
<Stack spacing={1} justifyContent={"center"} alignItems={"center"} className={styles["login-container"]}>
<TextField name={"id"} placeholder={"아이디를 입력해주세요."} required value={id} type={"text"} className={styles["login-input"]} onChange={inputsHandler} />
<TextField name={"password"} placeholder={"비밀번호를 입력하세요."} required value={password} type={"password"} className={styles["login-input"]} onChange={inputsHandler} />
</Stack>
<Stack>
<FormControlLabel control={<Checkbox checked={isRememberChecked} />} label={"아이디 저장"} className={styles.checkbox} onChange={checkboxHandler} />
</Stack>
<Stack justifyContent={"center"} alignItems={"center"}>
<Button type={"submit"} color={"primary"} variant={"contained"} className={styles["login-button"]} size={"large"} onClick={onLoginHandler}>
로그인
</Button>
</Stack>
<Stack justifyContent={"center"} alignItems={"center"} className={styles["error-message"]}>
<div>
{isError && (
<Alert severity={"error"}>
<strong>{isError}</strong>
</Alert>
)}
</div>
</Stack>
</Paper>
</Grid>
);
};
export default Login;
the warning is
Warning: Expected server HTML to contain a matching <div> in <div>.
at div
at eval (webpack-internal:///./node_modules/#emotion/react/dist/emotion-element-cbed451f.browser.esm.js:57:66)
at Box (webpack-internal:///./node_modules/#mui/system/esm/createBox.js:36:72)
at Layout (webpack-internal:///./layouts/Layout/index.tsx:16:26)
at InnerThemeProvider (webpack-internal:///./node_modules/#mui/system/esm/ThemeProvider/ThemeProvider.js:21:70)
at ThemeProvider (webpack-internal:///./node_modules/#mui/private-theming/ThemeProvider/ThemeProvider.js:47:5)
at ThemeProvider (webpack-internal:///./node_modules/#mui/system/esm/ThemeProvider/ThemeProvider.js:41:5)
at App (webpack-internal:///./pages/_app.tsx:61:27)
at ErrorBoundary (webpack-internal:///./node_modules/next/dist/compiled/#next/react-dev-overlay/client.js:8:20638)
at ReactDevOverlay (webpack-internal:///./node_modules/next/dist/compiled/#next/react-dev-overlay/client.js:8:23179)
at Container (webpack-internal:///./node_modules/next/dist/client/index.js:323:9)
at AppContainer (webpack-internal:///./node_modules/next/dist/client/index.js:820:26)
at Root (webpack-internal:///./node_modules/next/dist/client/index.js:944:27)
window.console.error # next-dev.js?3515:25
Case 1
Most likely a Server<>Client out of date issue.
Fix
If you are using the development server > Restart it.
If you are getting this production > Rebuild + Restart.
Case 2
The components you are using render differently (due to bad coding) on the Server (SSR) vs Client (CSR). This can be silenced by adding suppressHydrationWarning={true} to the offending component.
Case 3
Another case I've seen is that someone has set dangerouslySetInnerHtml with invalid HTML. The fix is to correct the HTML OR silence it as we did in case 2.
In my case I tried to run localStorage getItem method outside useEffect hook.
So probably you can place your async code inside that hook.
In progress value update from use hook can also causing this problem. To prevent it, just copy the variable value from hook to state from useEffect hook. Here is the example
import { useAccount } from "wagmi";
...
const { address, isConnected, isConnecting } = useAccount();
// the value of these variable above are changed dynamically
const [connectionStat, setConnectionStat] = useState();
const [addr, setAddr] = useState();
// copy the value to state here
useEffect(() => {
setConnectionStat(isConnected);
setAddr(address);
}, [address, isConnected])
// then now we can display the value properly
return (
<div>
<p>Connection status : {connectionStat}</p>
<p>Connected to : {addr}</p>
....
</div>
);
Explanation: passing value directly from hook to JSX/view may causing inconsistent value inside JSX/view so the the page render can not be consistent as well and there will be different value between value in SSR and client.
Hope it helps.

React - Share props between 2 components

I have a layout component that calls different components inside.
They are the header, breadcumbs , main and filter (sidebar left) and footer
I have a "filters" component that when selecting on the "select" I want it to send this information to the "categories" component.
That is, if in the component "filters" I filter by brand "FORD" I want the component "categories" to receive the brand "FORD"
The code like this works, but I can't pass the properties of the Filterheader component to the Name component (alias of category name)
Layout
import NavigationGuest from '#/components/Layouts/NavigationGuest'
import Footer from '#/components/Layouts/FooterGuest'
import { useRouter } from 'next/router'
import FilterHeader from "#/components/filters/Header";
const GuestLayout = ({ children }) => {
const router = useRouter()
return (
<div className="min-h-screen bg-gray-100">
<NavigationGuest />
<FilterHeaderNeveras />
{/* Page Content */}
<main>{children}</main>
<Footer />
</div>
)
}
export default GuestLayout
FilterHeader
import TextField from '#mui/material/TextField'
import Autocomplete from '#mui/material/Autocomplete'
import { useRouter } from 'next/router'
import { useState, useEffect } from 'react'
import axios from 'axios'
import Button from '#mui/material/Button'
const FilterHeaders = () => {
useRouter()
const [jsonResultBrands, setJsonResultBrands] = useState([])
const [selectMarca, setSelectMarca] = useState([])
const handleChangeBrand = (event, value) => {
setSelectMarca(value)
}
const handleButtonCLick = (event, value) => {
console.log(selectMarca)
}
useEffect(() => {
fetch(
'http://localhost:8000/api/productcategoryproperties/3/category/marca/type',
)
.then(response2 => response2.json())
.then(json2 => setJsonResultBrands(json2))
}, [])
return (
<div style={{ padding: '10px' }}>
<Autocomplete
onChange={handleChangeBrand }
disablePortal
id="combo-box-demo1"
key={jsonResultCalifEnergetica.id}
options={jsonResultBrands}
sx={{ width: '100%' }}
getOptionLabel={jsonResults => `${jsonResults.name}`}
renderInput={params => <TextField {...params} label="Brand" />}
/>
<Button variant="outlined" onClick={handleButtonCLick}>
Buscar
</Button>
</div>
)
}
export default FilterHeaders
Category Name
import Head from 'next/head'
import axios from 'axios'
import GuestLayout from '#/components/Layouts/GuestLayout'
import { useRouter } from 'next/router'
import Grid from '#mui/material/Grid'
import FilterHeaders from '#/components/filters/Header'
const Name = ({ itemsList }) => {
const router = useRouter()
return (
<GuestLayout>
<Head>
<title>Product Category {router.query.name}</title>
</Head>
<div className="py-12">
Filters: <br />
<FilterHeader />
</div>
</GuestLayout>
)
}
Name.getInitialProps = async () => {
const { data } = await axios.get('http://localhost:8080/api/category/1')
return { itemsList: data }
}
export default Name

Binding multipal row hang or crash web page using React with redux toolkit

https://codesandbox.io/s/large-data-array-with-redux-toolkit-forked-7tp63?file=/demo.tsx
In the given codesandbox example I am using react typescript with redux-toolkit
in codesandbox example. I am trying to bind countries with checkbox and textbox.
When I check on checkboxes it looks slow and textbox edit also feels very slow.
some time it breaks the page.
I am not sure what I am doing wrong.
You should make CountryItem it's own component and make it a pure component:
import React, { FC, useEffect } from "react";
import { createStyles, Theme, makeStyles } from "#material-ui/core/styles";
import List from "#material-ui/core/List";
import ListItem from "#material-ui/core/ListItem";
import ListItemText from "#material-ui/core/ListItemText";
import { countryList } from "./dummyData";
import { Checkbox, Grid, TextField } from "#material-ui/core";
import { useAppDispatch, useAppSelector } from "./store/hooks";
import {
setCountries,
setCountrySelected,
setCountryValue
} from "./store/slice/geography-slice";
import { Country } from "./interface/country.modal";
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
width: "100%",
backgroundColor: theme.palette.background.paper
}
})
);
const CountryItem: FC<{ country: Country }> = ({ country }) => {
console.log('render item',country.name)
const dispatch = useAppDispatch();
const handleCheckboxChange = (
event: React.ChangeEvent<HTMLInputElement>,
country: Country
) => {
const selectedCountry = { ...country, isSelected: event.target.checked };
dispatch(setCountrySelected(selectedCountry));
};
const handleTextChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const selectedCountry = { ...country, value: event.target.value };
dispatch(setCountryValue(selectedCountry));
};
return (
<ListItem button>
<Checkbox
checked={country?.isSelected ?? false}
onChange={(event) => {
handleCheckboxChange(event, country);
}}
/>
<ListItemText primary={country.name} />
<TextField value={country?.value ?? ""} onChange={handleTextChange} />
</ListItem>
);
};
const PureCountryItem = React.memo(CountryItem)
export default function SimpleList() {
const classes = useStyles();
const dispatch = useAppDispatch();
const { countries } = useAppSelector((state) => state.geography);
useEffect(() => {
dispatch(setCountries(countryList));
}, []);
return (
<div className={classes.root}>
<Grid container>
<Grid item xs={6}>
<List component="nav" aria-label="secondary mailbox folders">
{countries.map((country, index) => (
<PureCountryItem country={country} key={`CountryItem__${index}`} />
))}
</List>
</Grid>
</Grid>
</div>
);
}

Unable to display an API data using map function on Material UI tabs

I'm new to this programming world. Can anyone please help me on this.
I have implemented Material UI's tabs successfully by hard-coding the content, but when I tried to make my hard coded tabs with a .map function to populate the content from a data source (json), it no longer works. The tab displays nothing.
Here are the codes,
Planet component:
import React from 'react';
function Planet(props) {
return (
<ul>
<li>{props.name}</li>
</ul>
);
}
export default Planet;
Planets component:
import React, { useEffect, useState} from 'react';
import Planet from './Planet';
function Planets(props) {
const [planets, setPlanets] = useState([]);
useEffect(() => {
getPlanets();
}, []);
const getPlanets = async () => {
const response = await fetch("https://assignment-machstatz.herokuapp.com/planet");
const data = await response.json();
setPlanets(data);
}
return (
<div>
{planets.map((planet, index) => {
return (
<Planet key={index} name={planet.name} />
);
})}
</div>
);
}
export default Planets;
App component:
import React, { useState } from 'react';
import { AppBar, Tabs, Tab } from '#material-ui/core';
import Planet from './Planet';
import Favplanets from './Favplanets';
function App() {
const [selectedTab, setSelectedTab] = useState(0);
function handleChange (event, newValue) {
setSelectedTab(newValue);
}
return (
<>
<AppBar position="static">
<Tabs value={selectedTab} onChange={handleChange} >
<Tab label="Planets" />
<Tab label="Favourite Planets" />
</Tabs>
</AppBar>
{selectedTab === 0 && <Planet />}
{selectedTab === 1 && <Favplanets />}
</>
);
}
export default App;
Thanks for your help!

Resources