Set values first and then render the component - reactjs

I am new to learning React. The issue here is, my AAPost component gets rendered before I am setting the value of posts constant.
I tried to use async & await earlier but it wasn't helping at all. There must be something I am doing wrong, could someone point me in the right direction? Thank you :)
import React, { useEffect, useState } from 'react'
import './AAFeed.css'
import AAPost from './AAPost'
import AATweetBox from './AATweetBox'
import { db } from '../fbr'
function AAFeed() {
const [posts, setPosts] = useState([]);
useEffect(()=>{
db.collection('posts').onSnapshot((snapshot) => {
setPosts(snapshot.docs.map(doc => doc.data()));
});
},[])
return (
<>
<div className='feed'>
{/* Header */}
<div className='feed__feedtitle'>
<h2>Home Page</h2>
</div>
{/* Tweet Box */}
<AATweetBox />
{/* Tweets */}
{posts.forEach((post) => {
console.log('pp',post);
<AAPost
displayName={post.displayName}
username={post.username}
verified={post.verified}
timestamp={post.timestamp}
text={post.text}
image={post.image}
avatar={post.avatar}
/>
})
}
</div>
</>
)
}
export default AAFeed

I think mummo is because you are using forEach
forEach does not return a value
{ posts.map((post) => {
console.log('pp',post);
return(<AAPost
displayName={post.displayName}
username={post.username}
verified={post.verified}
timestamp={post.timestamp}
text={post.text}
image={post.image}
avatar={post.avatar}
/>) })}
Visit this site for information.

add this
before post.foreach and test it
if(post !== []){ post.foreach... }}

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>

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.

React elements get rendered twice

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.

Using forEach instead of map , trying to access objects in an Array

I am trying to build a React Recipe App. I am making API request for Recipe Search.
My question is about using map in this line
{recipes.map((recipe) => (
<Recipe />
))}
We are trying to access the objects inside of the array. Right? Yes, this works. However, I don't get why
{recipes.forEach ((recipe) => (
<Recipe />
))}
doesn't work. Could you please explain? The whole code is below.
App.js
import React, { useEffect, useState } from "react";
import Recipe from "./Recipe";
import "./App.css";
function App() {
const APP_ID = "xxxxxxxxxxx";
const APP_KEY = "yyyyyyyyyyyyyyyyyyy";
const [recipes, setRecipes] = useState([]);
useEffect(() => {
getRecipes();
}, []);
//yeni bir fonksiyon yazıyorum. take care of fetching all data
const getRecipes = async () => {
const response = await fetch(
`https://api.edamam.com/search?q=chicken&app_id=${APP_ID}&app_key=${APP_KEY}`
);
const data = await response.json();
setRecipes(data.hits);
};
return (
<div className="App">
<form className="search-form">
<input className="search-bar" type="text" />
<button className="search-button" type="submit">
Search
</button>
</form>
{recipes.map((recipe) => (
<Recipe />
))}
</div>
);
}
export default App;
Recipe.js
import React from "react";
const Recipe = () => {
return (
<div>
<h1>Title</h1>
<p>Calories</p>
<img src="" alt="" />
</div>
);
};
export default Recipe;
Because .map() returns the ARRAY of the <Recipe /> entities, and .forEach() doesn't return ANYTHING. React does not render by side-effect - it needs the JSX returned.
The forEach version doesn’t return an array of rendered elements like the map version does. The elements rendered inside the forEach don’t exist outside the scope of the forEach function, whereas the map version returns the elements in an array.

How to use a useState function in another component with props?

I write a React.js note web application where a user can add up to 10 notes.
I use map() to iterate the array of notes, and a useState(1) hook to update its count (the default number of notes is 1), so I would like to do something like this:
{[...Array(noteCount)].map((_, i) => <Note onUpdateNoteCount={() =>setNoteCount(n => n - 1)} key={i} />)}
The thing is that the Note() component is inside a Main() component which is in the App() component, so I want to get the needed values as props of App(), and than use them in Note(), but can not figure out how and where to put it.
Thanks!
App.js
import React from 'react';
import Header from './Header';
import Main from './Main';
function App () {
const [noteCount, setNoteCount] = React.useState(1);
function multiplyNoteComponent () {
if (noteCount < 20) {
setNoteCount(n => n + 1)
}
else {
alert('too many notes. remove or combine some of them together!')
}
}
return (
<div>
<Header/>
{[...Array(noteCount)].map((_, i) => <Main onUpdateNoteCount={() =>setNoteCount(n => n - 1)} key={i} />)}
<button
style={{left: '5%'}}
id='addNoteBtn'
onClick={multiplyNoteComponent}
title='Add a note'
>
+
</button>
</div>
);
}
export default App;
Main.js
import React from 'react';
import Note from './Note';
function Main () {
return (
<main>
your notes are:
<Note/>
</main>
)
}
export default Main;
Note.js
import React from 'react';
function Note () {
return (
<div> <button title='delete note' onClick={}>X</delete>
<li>
<input type='text'/>
</li>
</div>
)
}
export default Note
Edit: the reason I think I need the setNoteCount() function to be used in the Note() component, is for the count down when a note is being deleted (every note has its own delete button).
I would recommend this architecture of the your App.
Store the Notes array at the App level.
Add a note using NoteInput which adds a notes to your Notes array.
Map your Notes using the Note component which takes onDelete as a prop from App level.
Your App component should be responsible for storing and delete a note from the state.
In your example, notesCount is meant to a derivative state.
i.e it could be derived simply from the Notes array (notes.length).
So, rather than storing notesCount, I recommend storing notes and deriving count from it.
You could see the working example here :- https://stackblitz.com/edit/react-g19tei
import React from "react";
import "./style.css";
const NOTES_ALLOWED = 10;
export default function App() {
const [notes, setNotes] = React.useState([]);
function addNote(newNote) {
if (notes.length === NOTES_ALLOWED) {
alert(`Only ${NOTES_ALLOWED} notes are allowed to be added`)
} else {
setNotes([...notes, newNote]);
}
}
function handleDelete(deleteNoteIdx) {
const newNotes = [...notes];
// delete the note at the specific index
newNotes.splice(deleteNoteIdx, 1)
setNotes(newNotes);
}
return (
<div>
<div style={{ marginTop: 20, marginBottom: 20 }}>
<p>Your notes are</p>
{notes.map((note, idx) => (
<Note
note={note}
onDelete={() => handleDelete(idx)}
/>
))}
</div>
<NoteInput onAdd={addNote} />
</div>
);
}
function Note({ note, onDelete }) {
return (
<div>
<p>{note}
<button onClick={onDelete}>Delete Note</button>
</p>
</div>
)
}
function NoteInput({ onAdd }) {
const [note, setNote] = React.useState('');
function handleSubmit(e) {
e.preventDefault();
const noteToBeSend = note;
setNote('')
onAdd(noteToBeSend.trim());
}
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
value={note}
onChange={e => setNote(e.target.value)}
required
/>
<button type="submit">Add Note</button>
</form>
</div>
)
}

Resources