Can you tell me if my code is right or wrong? - reactjs

Page1 code
import React, { useState } from 'react'
import Header from '../Components/Header'
import MainQuiz from '../Components/MainQuiz'
const Turner = () => {
const [select, setSelect] = useState();
return (
<>
<Header />
<div className='text-center fs-3 text-uppercase'>Turner</div>
<div className="container p-5">
<select className="form-select" aria-label="Default select example" value={select} onChange={e => setSelect(e.target.value)}>
<option selected>Select The Quiz</option>
<option value="1">Turner 1</option>
<option value="2">Turner 2</option>
<option value="3">Turner 3</option>
<option value="4">Turner 4</option>
</select>
<MainQuiz value={select}/>
</div>
</>
)
}
export default Turner
Page2 code
import React, { useEffect, useState } from 'react'
const MainQuiz = (props) => {
const [data, setData] = useState([])
const url = `https://quizstcapi.herokuapp.com/turner/${props.value}`
useEffect(() => {
fetchData()
}, [])
const fetchData = () => {
fetch(url)
.then((res) => res.json())
.then((responce) => {
setData(responce);
})
}
return (
<div>
<h4> {props.value} </h4>
<h4> {url} </h4>
{data.map((item,i) => (
<>
<h3> {i} </h3>
<h3> {item.Question} </h3>
<h5> {item.Option1} </h5>
<h5> {item.Option2} </h5>
<h5> {item.Option3} </h5>
<h5> {item.Option4} </h5>
</>
))}
</div>
)
}
export default MainQuiz
I press ctrl+s in page 2 for fetch.
My problem is I cant fetch api directly. for fetch i need to choose option than come back to my code and press ctrl+s then it fetch the api i choose but i need is when i choose it directy show data of apis
here is the some images
after choosing
https://firebasestorage.googleapis.com/v0/b/trulyrockmusics.appspot.com/o/3.png?alt=media&token=a91f05f5-eff8-4f3b-aa53-324ed58f1c8e
after pressing ctrl+s
https://firebasestorage.googleapis.com/v0/b/trulyrockmusics.appspot.com/o/4.png?alt=media&token=7b7a9935-fa0c-4835-9c0f-705bc13ee124
Kindly give me a solution for this. thanks

Although your question is a bit hard to make sense of, my crystal ball is telling the issue is your data loading isn't aware of the value prop changing, since you compute url outside of the effect that actually loads the data.
Then, you'll need to make value a dependency of the effect, so when the value changes (when you change it in the select and pass it down to MainQuiz, the effect is re-run.
import React, {useEffect, useState} from 'react'
function MainQuiz({value}) {
const [data, setData] = useState(null);
useEffect(() => {
setData(null);
fetch(`https://quizstcapi.herokuapp.com/turner/${value}`)
.then((res) => res.json())
.then(setData);
}, [value]);
if (!data) return <>Loading...</>;
return (
<div>
{data.map(...)}
</div>
);
}

Related

Cannot display 1 image from a Array from a API

I can manage to display all and have them in roughly the right place with CSS, however in the case where there is more than 1 image, I cannot display just that first image
I eventually want to be able to click the image and display a Modal showing a gallery of these pics, but stuck on this part:
import React, { useState, useEffect } from "react";
import "./Hotel.css";
const URL = "https://obmng.dbm.guestline.net/api/hotels?collection-id=OBMNG";
const Hotel = () => {
const [hotel, setHotel] = useState([]);
useEffect(() => {
hotels();
}, []);
const hotels = async () => {
const response = await fetch(URL);
setHotel(await response.json());
};
// filter hotels button displayed by star rating
const filterHotels = (e) => {
const starRating = e.target.value;
const filteredHotels = hotel.filter(
(hotel) => hotel.starRating === starRating
);
setHotel(filteredHotels);
};
// store filteredHotels in state
const [filteredHotels, setFilteredHotels] = useState([]);
useEffect(() => {
setFilteredHotels(hotel);
}, [hotel]);
return (
<div>
<div className="selection-filter">
{/* drop down for useState */}
<label for="filter">Filter by star rating: </label>
<select onChange={filterHotels}>
<option value="0">All</option>
<option value="1">1 Star</option>
<option value="2">2 Star</option>
<option value="3">3 Star</option>
<option value="4">4 Star</option>
<option value="5">5 Star</option>
</select>
</div>
{hotel.map((data) => {
return (
<div>
<div className="list-group-item hotel-area" key={data.id}>
<div className="hotel-name">{data.name}</div>
{data.images.map((image) => (
<img
className="hotel-image"
src={data.images[0].url}
alt={image.alt}
/>
))}
<div className="hotel-address">{data.address1}</div>
<div className="hotel-address">{data.address2}</div>
<div className="star-rating fas fa-star">{data.starRating}</div>
<hr />
</div>
</div>
);
})}
</div>
);
};
export default Hotel;
It displays 3 images, because the first hotel object in the response object has 3 elements in the images array. If you want to show only one (first) image, don't use .map function, just render the first image, see this example.

The url is changing but it is not redirecting me

What I want is when I click on:
let Afeef = `/${category}`
<Link to={Afeef} className='products-categories'> <h4>{category}</h4></Link>
It should change products according to URL which could be "/electronics","/jewelry" etc but the problem I am facing is that it is changing my URL but the products are not changing. I can't understand what is the problem here. I tried different things but I cant understand it.
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))
}, [])
const [categories, setCategories] = useState([])
const updateCategory = async ()=> {
const url = "./categories.json"
let data = await fetch(url);
let parsedData = await data.json()
setCategories(parsedData.title)
}
useEffect(() => {
updateCategory();
}, [])
return (
<>
<div className="banner">
<h1>Afeef</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 = `/${category}`
return (
<Link to={Afeef} className='products-categories'> <h4>{category}</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>
</>
)
}
im gonna try to explain what i understand from your code. So based on the flow of your code, the product can only be fetch once when the page loaded.
but i think in your useEffect that fetch product, you can add the state of Categories in the bracket "[categories]".
then add an onclick setstate product in your link.
so when you click your link, the categories state is updated. then because the bracket inside useEffect that have [categories] is updated the useEffect is run. hence fething new product.

How can I default category through api

I have written a project which receives data through an api. Clicking on each button displays corresponding news. For example, when you press the sports button, sports news comes. However, I want the All category to be active when the page is first opened. In other words, those news should have arrived without pressing the all button. How can I do this?
Not - The function inside useffect returns every time it renders and it doesn't work for me. For example, when you refresh the page while reading sports news, all news comes
import React, { useEffect, useState } from "react";
import SpinnerLoad from './components/SpinnerLoad'
import NewsItem from "./components/NewsItem";
import Category from "./components/data/Category"
const App = () => {
const [state, setState] = useState([]);
const [loading, setLoading] = useState(false)
const fetchValue = (category) => {
fetch(`https://inshorts-api.herokuapp.com/news?category=${category}`)
.then(res => res.json())
.then(res => {
setState(res.data)
setLoading(true)
})
.catch((error) => console.log(error))
setLoading(false);
};
const CategoryButton = ({ category }) => (
<button onClick={() => fetchValue(category)} style={{ textTransform: 'capitalize' }}>{category}</button>
);
useEffect(() => {
fetchValue('all')
}, [])
return (
<>
<div className="header-bg">
<h1 className="mb-3">News</h1>
<div className="btns ">
{Category.map((value, index) => {
return <CategoryButton category={value} key={index} />;
})}
</div>
</div>
<div className="news">
<div className="container">
<div className="row">
{
!loading
? <SpinnerLoad/>
:
state.map((data,index) => {
return (
<NewsItem
imageUrl={data.imageUrl}
author={data.author}
title={data.title}
content={data.content}
date={data.date}
key={data.id}
/>
);
})
}
</div>
</div>
</div>
</>
);
};
export default App;
import React from 'react'
import clock from "../components/assets/img/Clock.svg"
import user from "../components/assets/img/User.svg"
const NewsItem = (props) => {
const {imageUrl, title, content, date, author} = props
return (
<div class="col-lg-4 col-md-6 col-12 p-2">
<div className="newsItem">
<img src={imageUrl} alt=''/>
<div className="itemBody">
<p className='title'>{title}</p>
<div className="line"></div>
<p className='content'>{content}</p>
<div className="itemfooter">
<h6><img src={clock} alt='clock'/>{date}</h6>
<h6><img src={user} alt='user'/>{author}</h6>
</div>
</div>
</div>
</div>
)
}
export default NewsItem
In react, if you refresh the app , the state values will reinitialise.
From your question , it seems like you want to store the category value and even after refresh , you want to persist the category value..
For that you can store category value in local or sessionStorage..
const fetchValue = (category) => {
localStorage.setItem("category", category);
// your code
}
// in useEffect , you can check for the category value in the local Storage
useEffect(() => {
// check value in localStorage, if does not exist use "all" as default value
let categoryValue = localStorage.getItem("category") || "all" ;
fetchValue(categoryValue)
},[]);

Trying to update deprecated/obsolete code for recent React/Redux versions

I have been following a tutorial to make a MERN e-commerce website:
Youtube Video Tutorial: VIDEO
Github containing all the code from the creator of the video: Github
And since it was published at December 2020, I encounter some deprecated/obsolete code that used to work for the creator of the video but doesn't work anymore.
I managed to solve most of the issues but at 3:31:26 of the video, he gets a bug and fixes it easily. The problem is that his solution doesn't make sense and it doesn't work. I have a different error but the error is logically generated. If you look at the video you will notice he does "cartItems.map" but when console logging cartItems it gives me that it is an object. I've tried replacing my code with his, but nothing. Replacing with his Github's code. Neither.
The error I receive when I click on "add to cart" from the product's page
This is where the web browser points to in the code, which is where cartItems is used as an array but it isn't (I also tried [...Array(cartItems)].map and didn't work
CartScreen.jsx
import './CartScreen.css'
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Link } from "react-router-dom";
// Components
import CartItem from "../components/CartItem";
const CartScreen = () => {
const dispatch = useDispatch();
const cart = useSelector(state => state.cart);
const { cartItems } = cart;
return (
<div className='cartscreen'>
<div className='cartscreen__left'>
<h2>Shopping Cart</h2>
{console.log(typeof cartItems)}
{cartItems.length === 0 ? (
<div>
Your Cart is empty <Link to="/">Go Back</Link>
</div>
) : (
cartItems.map((item) =>
<CartItem item={item} />
))}
</div>
<div className='cartscreen__right'>
<div className='cartscreen__info'>
<p>Subtotal (0) items</p>
<p>$499.99</p>
<div>
<button>Proceed to Checkout</button>
</div>
</div>
</div>
</div>
)
}
export default CartScreen;
CartItem.jsx
import "./CartItem.css";
import { Link } from "react-router-dom";
const CartItem = ({ item, qtyChangeHandler, removeHandler }) => {
return (
<div className="cartitem">
<div className="cartitem__image">
<img src={item.imageUrl} alt={item.name} />
</div>
<Link to={`/product/${item.product}`} className="cartItem__name">
<p>{item.name}</p>
</Link>
<p className="cartitem__price">${item.price}</p>
<select
value={item.qty}
onChange={(e) => qtyChangeHandler(item.product, e.target.value)}
className="cartItem__select"
>
{[...Array(item.countInStock).keys()].map((x) => (
<option key={x + 1} value={x + 1}>
{x + 1}
</option>
))}
</select>
<button
className="cartItem__deleteBtn"
onClick={() => removeHandler(item.product)}
>
<i className="fas fa-trash"></i>
</button>
</div>
);
};
export default CartItem;
cartActions.jsx
import * as actionTypes from '../constants/cartConstants';
import axios from 'axios';
export const addToCart = (id, qty) => async (dispatch, getState) => {
const { data } = await axios.get(`/api/products/${id}`);
dispatch({
type: actionTypes.ADD_TO_CART,
payload: {
product: data.id,
name: data.new,
imageURL: data.imageUrl,
price: data.price,
countInStock: data.countInStock,
qty
},
});
localStorage.setItem('cart', JSON.stringify(getState().cart.cartItems));
};
export const removeFromCart = (id) => (dispatch, getState) =>{
dispatch({
type: actionTypes.REMOVE_FROM_CART,
payload: id
});
localStorage.setItem('cart', JSON.stringify(getState().cart.cartItems));
};
ProductScreen.jsx
import "./ProductScreen.css";
import { useState, useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { useParams, useNavigate } from "react-router-dom";
// Actions
import { getProductDetails } from "../redux/actions/productActions";
import { addToCart } from "../redux/actions/cartActions";
const ProductScreen = ({ history }) => {
const [qty, setQty] = useState(1);
const dispatch = useDispatch();
const productDetails = useSelector((state) => state.getProductDetails);
const { loading, error, product } = productDetails;
const { id } = useParams();
const navigate = useNavigate();
useEffect(() => {
if (product && id !== product._id) {
dispatch(getProductDetails(id));
}
}, [dispatch, product]);
const addToCartHandler = () => {
dispatch(addToCart(product._id, qty));
navigate("/cart");
};
return (
<div className="productscreen">
{loading ? (
<h2>Loading...</h2>
) : error ? (
<h2>{error}</h2>
) : (
<>
<div className="productscreen__left">
<div className="left__image">
<img src={product.imageUrl} alt={product.name} />
</div>
<div className="left__info">
<p className="left__name">{product.name}</p>
<p>Price: ${product.price}</p>
<p>Description: {product.description}</p>
</div>
</div>
<div className="productscreen__right">
<div className="right__info">
<p>
Price:
<span>${product.price}</span>
</p>
<p>
Status:
<span>
{product.countInStock > 0 ? "In Stock" : "Out of Stock"}
</span>
</p>
<p>
Qty
<select value={qty} onChange={(e) => setQty(e.target.value)}>
{[...Array(product.countInStock).keys()].map((x) => (
<option key={x + 1} value={x + 1}>
{x + 1}
</option>
))}
</select>
</p>
<p>
<button type="button" onClick={addToCartHandler}>
Add To Cart
</button>
</p>
</div>
</div>
</>
)}
</div>
);
};
export default ProductScreen;
Nothing here is an obsolete style that "does not work any more" - if something doesn't work, it's not because of something being discontinued.
In this explicit case you should probably write something like
// change this
{cartItems.length === 0 ? (
// to this
{!cartItems || cartItems.length === 0 ? (
But generally, you are right, this is an outdated style of Redux and you will probably end up writing multiple times the amount of code than you would need to write if you were writing modern code. Modern Redux does not use switch..case reducers, ACTION_TYPES, you will not dispatch actions as objects directly etc. etc.
Please do yourself a favor and follow the official Redux tutorial instead and also look for other sources that teach up-to-date knowledge.

How do I loop through the Axios response to a table in React

I am trying to develop a mini project that retrieves the list of available listed jobs in React and Node as Backend. Little bit stuck at the response from the axios.
This is the response am getting from the axios response.
I want to display the array data into a table or list to show available jobs
Below is the code for that retrieves the data
import React, { useState, useEffect } from 'react'
import Layout from '../../core/Layout'
import axios from 'axios'
import { getCookie, isAuth, signout } from '../../auth/helpers';
const Find = () => {
const [values, setValues] = useState({
title:"",
duration:"",
durationSys:"",
budget:'',
addedBy:'',
category:'',
results:[],
searched: false
});
const { category} = values;
const token = getCookie('token');
const handleChange = category => event => {
console.log(event.target.value);
setValues({ ...values, [category]: event.target.value});
};
const handleClick = event =>{
event.preventDefault()
listJobs()
}
const listJobs = () =>{
axios.get( `${process.env.REACT_APP_API}/search-projects`,
{params: {category
}
})
.then(response => {
console.log('LOG SUCCESS --', response.data);
const data = response.data;
setValues({...values, results: data})
console.log('LOG STATE', data)
})
}
return (
<Layout>
<div class="form-group">
<label for="exampleFormControlSelect1">Category</label>
<select onChange={handleChange('category')} value={category} class="form-control"
id="exampleFormControlSelect1">
<option>--Select Category --</option>
<option value='Web Development'>Web Development</option>
<option value='Logo Design'>Logo Design</option>
<option value='Writing/Skills'>Writing/Skills</option>
<option value='Mobile App Development'>Mobile App Development</option>
<option value='SEO/Marketing'>SEO/Marketing</option>
</select>
</div>
<div class="d-flex justify-content-center">
<button onClick={handleClick} class="btn btn-default btn-info" style={{marginBottom: "15px"}}>Search</button>
</div>
<div>
<h5>List of available jobs</h5>
//here
</div>
</Layout>
)
}
export default Find;
Hi you can do something like this.
<ul>
(results || []).map((item, index) => <li key={index}> {item}</li>
</ul>
I would also suggest to convert your handleChange function ( and the rest ) to useCallback functions to reduce unnecessary updates.
Suppose job has some id, title and description:
{ results.map(( job, index ) => {
return (
<tr key={job.id}>
<td>{job.id}</td>
<td>{job.title}</td>
<td>{job.description}</td>
</tr>
);
})}
Or destructing:
{ results.map(({id, title, description}, index ) => {
return (
<tr key={id}>
<td>{id}</td>
<td>{jtitle}</td>
<td>{description}</td>
</tr>
);
})}
more info: https://flaviocopes.com/react-how-to-loop/

Resources