React elements get rendered twice - reactjs

The render function does not get called twice, but instead the elements of a list are duplicated, and after a refresh of the application everything works just fine and the duplicates disappear. It seems to be a corner case but I can't get my head around it. Also worth mentioning that once an element is deleted from the list, both the element and its duplicate dissapear.
What could possibly cause such a bug?
import React, { useContext, useEffect, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import {
fetchSavedInternships,
selectAllSavedInternships,
} from "./savedInternshipsSlice";
import { fetchInternships, selectAllInternships } from "../Anonymous/internshipsSlice";
import Loading from "../Universal/Loading";
import InternshipCard from "../Anonymous/InternshipCard";
import { v4 as uuidv4 } from "uuid";
import TabMenu from "../Universal/TabMenu";
const SavedInternships = () => {
const dispatch = useDispatch();
const savedInternships = useSelector(selectAllSavedInternships);
const statusSavedInternships = useSelector((state) => state.savedInternships.status);
const errorSavedInternships = useSelector((state) => state.savedInternships.error);
const internships = useSelector(selectAllInternships);
const statusInternships = useSelector((state) => state.internships.status);
const errorInternships = useSelector((state) => state.internships.error);
useEffect(() => {
let user = JSON.parse(sessionStorage.getItem("user"));
if (statusSavedInternships === "idle") {
dispatch(fetchSavedInternships(user.id));
}
if (statusInternships === "idle") {
dispatch(fetchInternships);
}
console.log("savedInternships");
}, []);
return (
<>
<TabMenu />
<br />
{(statusSavedInternships === "loading" || statusInternships === "loading") && (
<Loading />
)}
{statusSavedInternships === "succeeded" && (
<>
{savedInternships.length > 0 ? (
<div className="container">
<div className="row text-center ml-1">
<h5>Stagii salvate</h5>
</div>
<div className="row row-cols-2 row-cols-md-3 row-cols-lg-4">
{savedInternships.map((savedInternship) => (
<div key={uuidv4()} className="mb-3 col">
<div className="card">
<InternshipCard
internshipId={savedInternship.internshipId}
companyId={
internships.find((c) => c.id === savedInternship.internshipId)
?.companyId
}
/>
</div>
</div>
))}
</div>
</div>
) : (
<div className="text-center text-muted">Nu ai salvat niciun stagiu</div>
)}
</>
)}
{statusSavedInternships === "error" && <div>{errorSavedInternships}</div>}
</>
);
};
export default SavedInternships;

You can either check the value of savedInternships on first render and resolve issues with state part if there is any or you can implicitly put the respective dependencies you are checking in the useEffect, here you can check the mutation of statusSavedInternships and statusInternships prior getting into useEffect.

Related

Data is not displaying in react components

I don't understand why my fetched data is not displaying.
Data is fetched properly when i check by console.log() however nothing shows up in my JSX section. Code looks alight too. Anyone have idea what is wrong here?
import React from "react";
import { useEffect, useState } from "react";
import axios from "axios";
export const ConcertLatest = () => {
const [concerts, setConcerts] = useState([]);
useEffect(() => {
const loadConcerts = async () => {
const response = await axios.get("/data/concerts");
const rawData = response.data;
const filteredData = rawData.filter((concert) => {
//let date = new Date(concert.datum);
// let newestDate = new Date("2022-09-29");
return concert.datum >= "2022-09-30";
});
setConcerts(filteredData);
};
loadConcerts();
}, []);
if (!concerts.length) {
return <p>Loading...</p>;
}
console.log(concerts); // getting full populated objects
return (
<div>
<h1>Newest concerts </h1>
<div>
<div className="card">
<img src={concerts.image} style={{ width: 100 }} />
<div className="card-text">
<div>
{concerts.map((concert) => {
(<h1>{concert.name}</h1>), (<h2>{concert.datum}</h2>);
})}
</div>
</div>
</div>
</div>
</div>
);
};
Change syntax of map function, either use return keyword with curly braces or just use round braces without return keyword. Eg
<div>
{concerts.map((concert) => {
return (
<React.Fragment>
(<h1>{concert.name}</h1>), (<h2>{concert.datum}</h2>)
</React.Fragment>
)
})}
</div>
Or
<div>
{concerts.map((concert) => (
<React.Fragment>
(<h1>{concert.name}</h1>), (<h2>{concert.datum}</h2>)
</React.Fragment>
))}
</div>

useEffect conditional statement are not working

Here I am making a shopping app and I have a working cart in it and below is my code for my cart component and here in cart I want to render order button conditionally for that I have isFound state and first I am getting data from my redux store and then I am checking below in useEffect hook if my list is not empty(list is const where I am storing my redux fetched data) then I will set my state=true and initially it is false but the problem is that useEffect is chanigng state to true if there is nothing inside of my list const means even if cart is empty and even though I am setting useEfect dependency proprly as well but it is showing order button all the time so someone can please help thanks:
import { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
import classes from "./Cart.module.css";
const Cart = () => {
const navigate = useNavigate();
const [isFound, setIsFound] = useState(false);
const orders = useSelector((state) => state.data.DUMMY_DATA);
const list = orders.map(
(data, key) =>
data.product_count > 0 && (
<div className={classes.wrapper}>
<div className={classes.item}>
Item:   {data.product_name}{" "}
</div>
<div className={classes.amount}>
Amount:   {data.product_count}{" "}
</div>
<div className={classes.price}>
Price:   {data.product_price}
</div>
</div>
)
);
useEffect(() => {
if (list !== "") {
setIsFound(true);
}
}, [list]);
return (
<div className={classes.modal}>
<div className={classes.root}>
<span
className={classes.close}
onClick={() => navigate("/", { replace: true })}
>
×
</span>
{list}
{isFound && (
<div className={classes.order_button_wrapper}>
<button className={classes.order_button}>Order</button>
</div>
)}
</div>
</div>
);
};
export default Cart;
.map alway return an array. So list !== "" will alway be true.
Here is useEffect, you have an array not a string as list value:
useEffect(() => {
if (list.length > 0) {
setIsFound(true);
}
}, [list]);
You have placed a watcher on the list variable, that's why useEffect is not calling, you need to place a watcher on the state because the state is being rendered and when any changes to the state useEffect will be called, variable is not rendered That's is why useEffect is not being called and changes to your component are not being replicated. You have to create a state and put the list value in the state and you have to call the function in the useEffect because you only have one called otherwise your function will be calling, as you code below can see.
import { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
import classes from "./Cart.module.css";
const Cart = () => {
const navigate = useNavigate();
const [isFound, setIsFound] = useState(false);
const orders = useSelector((state) => state.data.DUMMY_DATA);
const [ordersList, setOrdersList] = useState("");
useEffect(() => {
const list = orders.map(
(data, key) =>
data.product_count > 0 && (
<div className={classes.wrapper}>
<div className={classes.item}>
Item:   {data.product_name}{" "}
</div>
<div className={classes.amount}>
Amount:   {data.product_count}{" "}
</div>
<div className={classes.price}>
Price:   {data.product_price}
</div>
</div>
)
);
setOrdersList(list);
}, [])
useEffect(() => {
if (ordersList !== "") {
setIsFound(true);
}
}, [ordersList]);
return (
<div className={classes.modal}>
<div className={classes.root}>
<span
className={classes.close}
onClick={() => navigate("/", { replace: true })}
>
×
</span>
{ordersList}
{isFound && (
<div className={classes.order_button_wrapper}>
<button className={classes.order_button}>Order</button>
</div>
)}
</div>
</div>
);
};
export default Cart;

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)
},[]);

Run useEffect only one when a special property changed

I want to update render when a special property changes. This property income from parents. I Made a useState called loader to handle codes when I have data or not. if the loader is false, my code calls API and if it is true render data.
First of all I use useEffect this way. It didn't update render
useEffect(() => {
callApi();
}, []);
After that I used useEffect this way. props.coordinates is a property that my code should update after it changes.
useEffect(() => {
callApi();
setLoader(false);
}, [props.coordinates]);
But my codes are in loops, and my API key was blocked.
Could you let me know what my mistake is ?
This my component:
import React, { useEffect, useState } from "react";
import axios from "axios";
import ForcastHour from "./ForcastHour";
import "./WeatherHourlyForcast.css";
const WeatherHourlyForcast = (props) => {
const [loader, setLoader] = useState(false);
const [hourlyForcastData, setHourlylyForcastData] = useState(null);
useEffect(() => {
callApi();
setLoader(false);
}, [props.coordinates]);
const showHourlyForcast = (response) => {
console.log("showHourlyForcast", response.data.hourly);
setHourlylyForcastData(response.data.hourly);
setLoader(true);
};
function callApi() {
let latitude = props.coordinates.lat;
let longitude = props.coordinates.lon;
const apiKey = "23422500afd990f6bd64b60f46cf509a";
let units = "metric";
let apiUrl = `https://api.openweathermap.org/data/2.5/onecall?lat=${latitude}&lon=${longitude}&appid=${apiKey}&units=${units}`;
axios.get(apiUrl).then(showHourlyForcast);
console.log("hourly", apiUrl);
}
if (loader) {
return (
<div className="row">
<div className="col-md-6">
<div className="row">
{hourlyForcastData.map(function (hourlyforcast, index) {
if (index < 4 && index > 0) {
return (
<div
className="col-4 box-weather my-auto text-center"
key={index}
>
<ForcastHour data={hourlyforcast} />
</div>
);
}
})}
</div>
</div>
<div className="col-md-6">
<div className="row">
{hourlyForcastData.map(function (hourlyforcast, index) {
if (index < 7 && index > 3) {
return (
<div
className="col-4 box-weather my-auto text-center"
key={index}
>
<ForcastHour data={hourlyforcast} />
</div>
);
}
})}
</div>
</div>
</div>
);
} else {
callApi();
return null;
}
};
export default WeatherHourlyForcast;
While adding dependencies array to the end of useEffect (or any other hook...), each render if the value is not equal to the prev one, the hook will run again.
Because props.coordinates is an object, and in JS objA != objA == true, even if the properties didn't change, React can't know that.
My suggestion is to use the values themselves (assuming they're strings either numbers and so on)
useEffect(() => {
(async () => {
await callApi();
setLoader(false);
})()
}, [props.coordinates.lat, props.coordinates.lon]);
Another thing that you might encounter is setLoader(false) will be called before callApi will be finished, therefore added async behaviour to the hook
You can write your component likes this and call the APIs when the component mount. The API calls happens when the lat, lon values are changed.
import React, { useEffect, useState } from "react";
import axios from "axios";
import ForcastHour from "./ForcastHour";
import "./WeatherHourlyForcast.css";
const WeatherHourlyForcast = (props) => {
const { coordinates : { lat, lon } } = props;
const [loader, setLoader] = useState(false);
const [hourlyForcastData, setHourlylyForcastData] = useState(null);
useEffect(() => {
callApi();
}, [lat, lon]); //It's call the API's when the lat, lon values are changed
const callApi = () => {
setLoader(true);
const latitude = lat;
const longitude = lon;
const apiKey = "23422500afd990f6bd64b60f46cf509a";
const units = "metric";
const apiUrl = `https://api.openweathermap.org/data/2.5/onecall?lat=${latitude}&lon=${longitude}&appid=${apiKey}&units=${units}`;
axios.get(apiUrl).then((response) => {
console.log(response.data);
console.log(response.status);
console.log(response.statusText);
console.log(response.headers);
console.log(response.config);
console.log("showHourlyForcast", response.data.hourly);
setHourlylyForcastData(response.data.hourly);
setLoader(false);
});
};
if (loader) {
return (
<div>
<h1>Loading...</h1>
</div>
);
}
return (
<div className="row">
<div className="col-md-6">
<div className="row">
{hourlyForcastData.map(function (hourlyforcast, index) {
if (index < 4 && index > 0) {
return (
<div
className="col-4 box-weather my-auto text-center"
key={index}
>
<ForcastHour data={hourlyforcast} />
</div>
);
}
})}
</div>
</div>
<div className="col-md-6">
<div className="row">
{hourlyForcastData.map(function (hourlyforcast, index) {
if (index < 7 && index > 3) {
return (
<div
className="col-4 box-weather my-auto text-center"
key={index}
>
<ForcastHour data={hourlyforcast} />
</div>
);
}
})}
</div>
</div>
</div>
);
};
export default WeatherHourlyForcast;

Pass props to component: "Objects are not valid as a React child"

I'm trying to simply pass the Id of a clicked item to display on another page under a different component ("Cart") . At the bottom of the code below, I have a button containing <Cart test={product.id} /> which extracts the Id that I want to be displayed in "Cart" when the button is clicked.
However, I am instead getting an error message of:
Objects are not valid as a React child (found: object with keys
{history, location, match, staticContext}). If you meant to render a
collection of children, use an array instead.
Is there a simple syntax error?
import React, { useState, useEffect, Cart } from 'react';
import './../App.css';
import * as ReactBootStrap from 'react-bootstrap';
function Item(props) {
const [product, setProduct] = useState([]);
const [loading, setLoading] = useState(false);
const [quantity, setQuantity] = useState(1);
const [cost, setCost] = useState([]);
useEffect(async () => {
fetchItems();
}, []);
const itemId = props.match.params.item;
const fetchItems = async () => {
const data = await fetch('https://fakestoreapi.com/products/' + itemId);
const items = await data.json();
setProduct(items);
setLoading(true);
setCost(items.price);
};
function priceUSD(change) {
return change.toFixed(2);
}
useEffect(() => {
const newCost = quantity * product.price;
setCost(priceUSD(newCost));
}, [quantity]);
return (
<div className="App">
<h2>Item</h2>
<div className="gridContainer">
{loading ? (
<div key={itemId} className="productStyle">
<img src={product.image} className="productImage"></img>
<p>{product.title}</p>
<p>{product.description}}</p>
<p>${priceUSD(product.price)}</p>
<div className="quantity">
<button
className="btn minus-btn"
type="button"
onClick={quantity > 1 ? () => setQuantity(quantity - 1) : null}
>
-
</button>
<input type="text" id="quantity" value={quantity} />
<button className="btn plus-btn" type="button" onClick={() => setQuantity(quantity + 1)}>
+
</button>
</div>
<button type="button" onClick={() => <Cart test={product.id} />}>
Add to shopping cart ${cost}
</button>
</div>
) : (
<ReactBootStrap.Spinner className="spinner" animation="border" />
)}
</div>
</div>
);
}
export default Item;
Cart
import React, { useState, Item } from 'react';
import './../App.css';
import './Item.js';
function Cart(test) {
return (
<div className="App">
<p>{test}</p>
</div>
);
}
export default Cart;
Component props are objects. You can read more about them in the official documentation.
You can either destructure the props of the Cart component:
function Cart({test}) {
return (
<div className="App">
<p>{test}</p>
</div>
);
}
or use explicitly test property of props:
function Cart(props) {
return (
<div className="App">
<p>{props.test}</p>
</div>
);
}

Resources