I ma creating app to get pokemons, first I save them in a list and after that show them, but I am getting empty card and after that the same pokemn is showing even if I am searching for another one.
Also I am getting distortion view when I use my component
import { useState, useEffect } from "react";
import "./App.css";
import { v4 } from "uuid";
import Button from "./Components/Button";
import Input from "./Components/Input";
import Label from "./Components/Label";
import Card from "./Components/Card";
import axios from "axios";
function App() {
// const [textFromInput, setTextFromInput] = useState("");
const [name, setName] = useState("");
const [nameFromButtonClick, setNameFromButtonClick] = useState("");
const [pokemon, setPokemon] = useState({
name: "",
picture: "",
id: 0,
type1: "",
type2: "",
});
const [list, setList] = useState([]);
const handleChange = (event) => setName(event.target.value);
const handleClick = () => {
setNameFromButtonClick(name);
setList([...list, pokemon]);
};
// const handleClick = () => setList([...list, pokemon]);
useEffect(() => {
axios
.get(`https://pokeapi.co/api/v2/pokemon/${name}/`)
.then((res) => {
console.log(res);
// setPokemon(res.data);
console.log("res.data=>", res.data);
setPokemon({
name: res.data.name,
picture: res.data.sprites.front_default,
id: res.data.id,
type1: res.data.types[0].type.name,
type2: res.data.types[1].type.name,
});
})
.catch((err) => {
console.log(err);
});
}, [nameFromButtonClick]);
return (
<div className="App">
<div>
<h1>Pokémon Effect</h1>
</div>
<div className="centered">
<div className="container">
{list.map((entry) => (
<Card key ={v4()}
name={entry.name}
picture={entry.picture}
id={entry.id}
type1={entry.type1}
type1={entry.type2}
/>
))}
</div>
<div className="dashboard">
<Input className="input" value={name} onChange={handleChange} />
<Button
className="getPokemon"
text="GetPokemon"
onClick={handleClick}
/>
<Label text={name} />
</div>
</div>
</div>
);
}
export default App;
this is my component Card, I don't know how to make it look like when I ma writing directly in app.js
export default function Card(props){
const{name, picture,id,type1,type2}=props
return(
<div className="card">
<div><img src={picture} alt={name} /></div>
<p>n:{id}</p>
<div> name={name}</div>
<div className="pokeType">
<div className="classType">type={type1}</div>
<div className="classType">type={type2}</div>
</div>
</div>
)
}
Related
I'm making a note taking app. I have an array set to state that holds the notes and each note is set to state as an object. My NoteList component maps over the array to render a new Note component when the save button is pressed. Everything works so far, except for the first note. When the first note is saved, the delete button renders but not the user input or date. On every subsequent save, everything renders how it should. I've looked over my code but I'm not sure what is causing this. Can someone please point me in the right direction?
import { useState } from 'react';
import uniqid from 'uniqid';
import NoteList from './components/NoteList';
function App() {
const [note, setNote] = useState({
note: '',
date: '',
id: ''
})
const [notes, setNotes] = useState([])
const [error, setError] = useState(false);
function handleAddNote(text) {
const date = new Date();
const newNote = {
text: text,
date: date.toLocaleDateString(),
id: uniqid()
}
setNote(newNote);
const newNotes = [
...notes,
note
]
setNotes(newNotes);
}
return (
<div className="App">
<h1>My Notes</h1>
<input placeholder='Type to search...'></input>
<NoteList notes={notes} handleAddNote={handleAddNote}/>
</div>
);
}
export default App;
import Note from './Note'
import AddNote from './AddNote'
function NoteList({ notes, handleAddNote }) {
return (
<div className='list-container'>
{notes.map((note) => (
<Note text={note.text} id={note.id} date={note.date}
key={note.id} notes={notes} note={note}/>
))}
<AddNote handleAddNote={handleAddNote}/>
</div>
)
}
export default NoteList;
function Note({ note }) {
return (
<div className='note-container'>
<span className='note-text'>{note.text}</span>
<div className='note-footer'>
<p className='note-date'>{note.date}</p>
<button>Delete</button>
</div>
</div>
)
}
export default Note;
import { useState } from 'react';
function AddNote({ handleAddNote } ) {
const [noteText, setNoteText] = useState('');
function handleChange(e) {
setNoteText(e.target.value);
}
function handleSaveNote() {
if (noteText) {
handleAddNote(noteText);
setNoteText('');
}
}
return (
<div className='new-note-container'>
<textarea onChange={handleChange} value={noteText}
rows='5' cols='30' placeholder='Type to enter a note...'
</textarea>
<div className='count-container'>
<p>Character Count</p>
<button onClick={handleSaveNote}>Save</button>
</div>
</div>
)
}
export default AddNote;
I think that the thing you are missing is that after calling setNote it does not change note on the current render. Only in the next render for that component note will get the new state.
In your case I don't see way you need to have a state for the new note so you can change your App component to be something like this:
function App() {
const [notes, setNotes] = useState([])
const [error, setError] = useState(false);
function handleAddNote(text) {
const date = new Date();
const newNote = {
text: text,
date: date.toLocaleDateString(),
id: uniqid()
}
setNotes((prevNotes) => [...prevNotes, newNote]);
}
return (
<div className="App">
<h1>My Notes</h1>
<input placeholder='Type to search...'></input>
<NoteList notes={notes} handleAddNote={handleAddNote}/>
</div>
);
}
All of these functions, such as adding notes, deleting notes, and searching for notes, are implemented in this code and work properly. I think this might be helpful for you!
import { useState } from "react";
import { uuid } from "uuidv4";
const SelectChip = () => {
const [notes, setNotes] = useState([]);
const [searchTerm, setSearchTerm] = useState("");
function handleAddNote(text) {
const date = new Date();
setNotes((prev) => [
...prev,
{
text: text,
date: date.toLocaleDateString(),
id: uuid()
}
]);
}
return (
<div className="App">
<h1>My Notes</h1>
<input
value={searchTerm}
onChange={(event) => setSearchTerm(event.target.value)}
placeholder="Type to search..."
/>
<NoteList
notes={notes}
setNotes={setNotes}
handleAddNote={handleAddNote}
search={searchTerm}
/>
</div>
);
};
export default SelectChip;
function NoteList({ notes, setNotes, handleAddNote, search }) {
const filteredItems = notes.filter((item) =>
item.text.toLowerCase().includes(search.toLowerCase())
);
return (
<div className="list-container">
{filteredItems.map((note) => {
return (
<Note
text={note.text}
id={note.id}
date={note.date}
key={note.id}
setNotes={setNotes}
note={note}
/>
);
})}
<AddNote handleAddNote={handleAddNote} />
</div>
);
}
function Note({ note, setNotes }) {
function handleDelete(noteId) {
setNotes((prev) => prev.filter((note) => note.id !== noteId));
}
return (
<div className="note-container">
<span className="note-text">{note.text}</span>
<div className="note-footer">
<p className="note-date">{note.date}</p>
<button onClick={() => handleDelete(note.id)}>Delete</button>
</div>
</div>
);
}
function AddNote({ handleAddNote }) {
const [noteText, setNoteText] = useState("");
function handleChange(e) {
setNoteText(e.target.value);
}
function handleSaveNote() {
if (noteText) {
handleAddNote(noteText);
setNoteText("");
}
}
return (
<div className="new-note-container">
<textarea
onChange={handleChange}
value={noteText}
rows="5"
cols="30"
placeholder="Type to enter a note..."
></textarea>
<div className="count-container">
<p>Character Count</p>
<button onClick={handleSaveNote}>Save</button>
</div>
</div>
);
}
I have problem with rendering data from local storage on every refresh or reload. It renders only hard coded data but not data that I save in LS. It shows data in LS but not rendering. If anyone could explain or tell me what is wrong or give me directions to do something better would be grateful.I am farely new in Reactand would apretiate for insights. I ve put some dummy data. I ve sent componnets which could affect.
import { useState, useEffect } from "react";
//COMPONENTS:
import ScrollToTop from "./components/ScrollToTop";
import Footer from "./components/Footer";
import Home from "./components/Home";
import NavBar from "./components/NavBar";
import PhoneBook from "./components/PhoneBook";
function App() {
const date = new Date().toLocaleDateString();
const [contacts, setContacts] = useState([
{
id: Math.random().toString(36).substr(2, 9),
fullName: "Vekjko Petrovic",
address: "121 Town Commons Way Phoenix, AZ, 45215",
phone: 123_465_689,
date,
},
{
id: Math.random().toString(36).substr(2, 9),
fullName: "Marko Petrovic",
address: "Srbina 35, 11300 Smederevo Srbija",
phone: 256_269_866,
date,
},
{
id: Math.random().toString(36).substr(2, 9),
fullName: "Michael Jackson",
address: "52 City St, Detroit, Mi, 46218",
phone: 359_525_555,
date,
},
{
id: Math.random().toString(36).substr(2, 9),
fullName: "Vanessa Parady",
address: "11 Beogradska Beograd, SRB, 11000",
phone: 123_465_689,
date,
},
]);
useEffect(() => {
const savedContacts = JSON.parse(localStorage.getItem("contacts"));
if (savedContacts) {
setContacts(savedContacts);
}
}, []);
useEffect(() => {
localStorage.setItem("contacts", JSON.stringify(contacts));
}, [contacts]);
const [searchContact, setSearchContact] = useState("");
const [theme, setTheme] = useState("dark");
const changeTheme = () => {
theme === "dark" ? setTheme("light") : setTheme("dark");
};
const addContact = (fullName, phone, address, email) => {
const newContacts = {
id: Math.random().toString(36).substr(2, 9),
fullName,
address,
phone,
email,
date,
};
const newContact = [...contacts, newContacts];
setContacts(newContact);
};
const deleteContact = (id) => {
const remainedContacts = contacts.filter((item) => item.id !== id);
setContacts(remainedContacts);
};
return (
<div data-theme={theme} className="app-container">
<ScrollToTop />
<NavBar changeTheme={changeTheme} currentTheme={theme} />
<Home />
<PhoneBook
contacts={contacts.filter((contact) =>
contact.fullName.toLowerCase().includes(searchContact)
)}
handleAddContact={addContact}
deleteContact={deleteContact}
handleSearchContacts={setSearchContact}
/>
<Footer />
</div>
);
}
export default App;
import React from "react";
import "../index.css";
//ASSETS:
import NewContact from "./NewContact";
import Contact from "./Contact";
import Search from "./Search";
function PhoneBook({
contacts,
handleAddContact,
deleteContact,
handleSearchContacts,
}) {
return (
<div id="phone_book" className="contacts-list">
<Search handleSearchContacts={handleSearchContacts} />
{contacts.map((contact) => {
return (
<Contact
key={contact.id}
id={contact.id}
fullName={contact.fullName}
address={contact.address}
phone={contact.phone}
email={contact.email}
date={contact.date}
deleteContact={deleteContact}
/>
);
})}
<NewContact handleAddContact={handleAddContact} />
</div>
);
}
export default PhoneBook;
import React from "react";
import profile from "../assets/images/profile.png";
import { MdDeleteForever } from "react-icons/md";
function Contact({ fullName, address, phone, email, id, date, deleteContact }) {
return (
<div className="contact">
<p className="contact-header">
<span>
<i>{fullName} </i>
</span>
<img src={profile} alt="profile" />
</p>
<div className="contact-footer">
<p>
{" "}
<i>Address: </i>
{address}
</p>
<p>
<i>Phone:</i> {phone}
</p>
<p>
{" "}
<i>Email:</i> {email}
</p>
<MdDeleteForever
onClick={() => deleteContact(id)}
className="delete-icon"
size="1.3rem"
/>
<p className="span-date">
<i>Date: </i>
{date}
</p>
</div>
</div>
);
}
export default Contact;
import React, { useState } from "react";
function NewContact({ handleAddContact }) {
const [fullName, setFullName] = useState("");
const [phone, setPhone] = useState("");
const [address, setAddress] = useState("");
const [email, setEmail] = useState("");
const handleSaveClick = () => {
if (!(fullName.trim().length > 0)) {
return;
}
handleAddContact(fullName, phone, address, email);
setFullName("");
setPhone("");
setAddress("");
setEmail("");
};
return (
<div className="contact new last">
{" "}
<p className="inputs">
<span>Create New Contact</span>
<label>Full Name:</label>
<input
type="text"
placeholder="Enter..."
value={fullName}
onChange={(e) => setFullName(e.target.value)}
/>
<label> Address:</label>
<input
type="text"
placeholder="Enter..."
value={address}
onChange={(e) => setAddress(e.target.value)}
/>
<label> Phone:</label>
<input
type="text"
placeholder="Enter..."
value={phone}
onChange={(e) => setPhone(e.target.value)}
/>
<label>Email:</label>
<input
type="text"
placeholder="Enter..."
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</p>
{/* <img src={profile} alt="fullname" /> */}
<div className="save-list-footer">
<button className="save" onClick={handleSaveClick}>
SAVE
</button>
</div>
</div>
);
}
export default NewContact;
import styled from "styled-components";
import React from "react";
import { MdSearch } from "react-icons/md";
//STYLES
import "../index.css";
function Search({ handleSearchContacts }) {
return (
<SearchComponent className="search">
<MdSearch className="search-icon" size="1.3em" />
<input
type="text"
placeholder="Search..."
onChange={(e) => handleSearchContacts(e.target.value)}
/>
</SearchComponent>
);
}
export default Search;
Took me some messing around but I think I have an example that might be doing what you are describing. It seems like the following code may be the culprit:
useEffect(() => {
localStorage.setItem("contacts", JSON.stringify(contacts));
}, [contacts]);
Not in your example I assume you are initializing contacts like such:
const [contact, setContacts] = useState([])
When this state is initialized it will trigger that useEffect and set the localStorage.setItem("contacts" , []) which will make it look like nothing is being rendered. I think the easiest fix would be to move the localStorage.setItem into the addContacts function.
Here is a simplified version of how to set it up:
export const Contacts = () => {
const [contacts, setContacts] = useState([]);
useEffect(() => {
const savedContacts = localStorage.getItem("contacts");
if (savedContacts) {
setContacts(JSON.parse(savedContacts));
}
}, []);
// useEffect(() => {
// //This is your issue here Comment out this block and comment in the setItem in the addContact
// localStorage.setItem("contacts", JSON.stringify(contacts));
// }, [contacts]);
const addContact = (newContact) => {
const newContactList = [...contacts, newContact];
setContacts(newContactList);
localStorage.setItem("contacts", JSON.stringify(newContactList));
};
return (
<div>
<InputContact addContact={addContact} />
{contacts.map((data, i) => (
<Contact data={data} key={i} />
))}
</div>
);
};
You can find a working example of this on code sandbox. There is some explanation of the app in the App.js and Contacts.jsx. https://codesandbox.io/s/localstorage-contacts-s9dfzc?file=/src/Contacts.jsx:130-969
I am creating a react app which is using local storage. I am saving and array of objects to local storage.
when I try to save to local storage the data is saving.
and then when I refresh the page the saved data is becoming empty object,
like this [].
if any one knows why its happening please help me
import React, {useEffect, useState} from 'react';
import Addcontact from './Addcontact';
import './App.css';
import Contactlist from './Contactlist';
import { Header } from './Header';
function App() {
const keyy ="contactlist"
const [contacts, setcontacts] = useState([])
const contactshandler = (contact)=> {
console.log(contact)
setcontacts([...contacts, contact])
}
useEffect(() => {
const getdata = JSON.parse(localStorage.getItem(keyy))
getdata && setcontacts(getdata)
}, [])
useEffect(() => {
localStorage.setItem(keyy, JSON.stringify(contacts));
}, [contacts])
return (
<div className="ui container">
<Header />
<Addcontact contacts={contacts} contactshandler={contactshandler} />
<Contactlist contacts={contacts} />
</div>
);
}
app component
import React, { useState } from 'react'
function Addcontact({contacts, setcontacts, contactshandler}) {
const [user, setuser] = useState({username:'', email:''})
const addvalue = (e) => {
e.preventDefault();
console.log(user)
contactshandler(user)
setuser({username:'', email:''})
}
return (
<div>
<div className='ui main'>
<h2> Add Contact</h2>
<form className='ui form' onSubmit={addvalue}>
<div className=''>
<label>name</label>
<input name="name" placeholder='name' value={user.username} onChange={(e) => setuser({...user, username : e.target.value })} />
</div>
<div className='feild'>
<label>email</label>
<input email='email' placeholder='email' value={user.email} onChange={(e) => setuser({...user, email: e.target.value})} />
</div>
<button>add</button>
</form>
</div>
</div>
)
}
export default Addcontact
export default App;
add component
this is the value showing when saving after refresh this value becomes empty object
enter image description here
console
enter image description here
You don't need useEffect to read the data. You can initially read it.
const [contacts, setcontacts] = useState(JSON.parse(localStorage.getItem(keyy)) ?? [])
and remove
useEffect(() => {
const getdata = JSON.parse(localStorage.getItem(keyy))
getdata && setcontacts(getdata)
}, [])
On my products list page when i click on view icon underneath the product thumbnail it takes me to a blank product details page.the product detail page has the right id but doesn't display anything
This is my code for the product details page.
import { useState, useEffect } from 'react';
import {useParams} from 'react-router-dom';
const axios = require('axios');
const SingleProduct = () => {
const [data, setData] = useState([]);
const params = useParams();
useEffect(() => {
fetchProduct();
}, []);
const fetchProduct = () => {
axios
.get(
`http://localhost:5000/api/products/${params._id}`
)
.then((res) => {
setData(res.data);
console.log(res.data);
})
.catch((err) => console.log(err))
;
};
return (
<div>
{data.map((item) => {
return (
<div className='product-container' key={item._id}>
<div>
<img className='prod-image' src={item.imageUrl} alt='' />
</div>
<div>
<h1 className='brand'>{item.name}</h1>
<h2>{item.price}</h2>
<p>{item.description}</p>
<p>
<strong>Price:</strong> {item._id}
</p>
<p>
<strong>Color:</strong> {item.color}
</p>
</div>
</div>
);
})}
</div>
);
;
}
export default SingleProduct;
This is the code in App.js:
<Route path='/SingleProduct/:_id' element={SingleProduct} />
This the code in the products list page:
import React from 'react'
import {useEffect} from 'react';
import {Link} from 'react-router-dom'
const ProductsPage = (props) => {
const items = props.items;
const getItems = props.getItems;
useEffect(() => {
getItems();
}, [])
return (
<>
<section className="ProductsPage items-page" onload = {getItems}>
{items.filter (item => item.price < 1000).map(item => (
<ul items-style>
<img src={item.imageUrl} alt="product" />
<h2>{item.name}</h2>
<Link to={`/SingleProduct/${item._id}`}>View</Link>
</ul>
//
))}
</section>
</>
) }
export default ProductsPage
I have started learning React.js and i have covered basic concepts like React States, working and events.
just encountered a problem in rendering my data on the screen dynamically
here is the code.
Description: I am trying to create a very small SPA in which the user can enter the name of expense(title), the amount spent(amount), and the date of expense(date).
the user can then add these expenses using the add expense button and it should then be updated as a new expense component in the SPA.
problem: The dummy data(static data from an array) is rendered on the screen.
when I try to add a new expense, this new expense is displayed with the title from the DUMMY_DATA array.
what I want: whenever a user enters a new expense, then this new expense should be added with the entered data, not from DUMMY_DATA.
----APP.JS-----
import React, { useState } from "react";
import Expenses from "./components/Expenses/Expenses";
import NewExpense from "./components/NewExpense/NewExpense";
const DUMMY_EXPENSES = [
{
id: "e1",
title: "Toilet Paper",
amount: 94.12,
date: new Date(2020, 7, 14),
},
{ id: "e2", title: "New TV", amount: 799.49, date: new Date(2021, 2, 12) },
{
id: "e3",
title: "Car Insurance",
amount: 294.67,
date: new Date(2021, 2, 28),
},
{
id: "e4",
title: "New Desk (Wooden)",
amount: 450,
date: new Date(2021, 5, 12),
},
];
const App = () => {
const [expenses, setExpenses] = useState(DUMMY_EXPENSES);
const addExpenseHandler = (expense) => {
setExpenses((previousExpenses) => {
return [expense, ...previousExpenses];
});
};
return (
<div>
<NewExpense onAddExpense={addExpenseHandler} />
<Expenses items={expenses} />
</div>
);
};
export default App;
-----NEW EXPENSE------
import React from "react";
import "./NewExpense.css";
import ExpenseForm from "./ExpenseForm";
const NewExpense = (props) => {
const saveExpenseDataHandler = (enteredExpenseData) => {
const expenseData = { ...enteredExpenseData, id: Math.random().toString() };
console.log("------new expense-------");
console.log(expenseData);
props.onAddExpense(expenseData);
};
return (
<div className="new-expense">
<ExpenseForm onSaveExpenseData={saveExpenseDataHandler} />
</div>
);
};
export default NewExpense;
------EXPENSES------
import "./Expenses.css";
import ExpenseItem from "./ExpenseItem";
import Card from "../UI/Card";
import ExpensesFilter from "./ExpensesFilter";
const Expenses = (props) => {
const filterChangeHandler = (selectedYear) => {
console.log("in expenses.js");
console.log(selectedYear);
};
return (
<div>
<Card className="expenses">
<ExpensesFilter onChangeFilter={filterChangeHandler} />
{props.items.map((expense) => (
<ExpenseItem
title={expense.title}
amount={expense.amount}
date={expense.date}
/>
))}
</Card>
</div>
);
};
export default Expenses;
------EXPENSE FORM------
import "./ExpenseForm.css";
import React, { useState } from "react";
const ExpenseForm = (props) => {
const [enteredTitle, setEnteredTitle] = useState("");
const [enteredAmount, setEnteredAmount] = useState("");
const [enteredDate, setEnteredDate] = useState("");
const titleChangeHandler = (event) => {
setEnteredTitle(event.target.value);
// console.log(event.target.value);
};
const amoundChangeHandeler = (event) => {
setEnteredAmount(event.target.value);
};
const dateChangeHandeler = (event) => {
setEnteredDate(event.target.value);
};
const submitHandler = (event) => {
event.preventDefault();
const expenseData = {
title: enteredTitle,
amount: enteredAmount,
date: new Date(enteredDate),
};
console.log("--------expense form---------");
console.log(expenseData);
props.onSaveExpenseData(expenseData);
setEnteredTitle("");
setEnteredAmount("");
setEnteredDate("");
};
return (
<form onSubmit={submitHandler}>
<div className="new-expense__controls"></div>
<div className="new-expense__control "></div>
<label className="new-expense__control label">Title</label>
<input type="text" value={enteredTitle} onChange={titleChangeHandler} />
<div className="new-expense__controls"></div>
<div className="new-expense__control"></div>
<label>Amount</label>
<input
type="number"
value={enteredAmount}
min="0.01"
step="0.01"
onChange={amoundChangeHandeler}
/>
<div className="new-expense__controls"></div>
<div className="new-expense__control"></div>
<label>Date</label>
<input
type="date"
value={enteredDate}
min="2019-01-01"
max="2022-12-31"
onChange={dateChangeHandeler}
/>
<div className="new-expense__actions">
<button type="submit">Add Expense</button>
</div>
</form>
);
};
export default ExpenseForm;
------EXPENSE ITEM------
import userEvent from "#testing-library/user-event";
import React, { useState } from "react";
import "./ExpenseItem.css";
import ExpenseDate from "./ExpenseDate";
import Card from "../UI/Card";
const ExpenseItem = (props) => {
const [title, setTitle] = useState(props.title);
const clickHandeler = () => {
setTitle("Updated!");
};
return (
<Card className="expense-item">
<ExpenseDate date={props.date} />
<div className="expense-item__description">
<h2>{title}</h2>
</div>
<div className="expense-item__price">${props.amount}</div>
<button onClick={clickHandeler}>Change Title</button>
</Card>
);
};
export default ExpenseItem;
here are some snapshots.
1-> initial state
this is the initial state after saving the code and opening it in the browser
2-> here is the data i am going to add
3->error state. i want a a new expense to be formed(abcd) and to show the title amount and date with it
------EXPENSES------
syntax error in rendering title in block
it is props.title instead of just title
import userEvent from "#testing-library/user-event";
import React, { useState } from "react";
import "./ExpenseItem.css";
import ExpenseDate from "./ExpenseDate";
import Card from "../UI/Card";
const ExpenseItem = (props) => {
const [title, setTitle] = useState(props.title);
const clickHandeler = () => {
setTitle("Updated!");
};
return (
<Card className="expense-item">
<ExpenseDate date={props.date} />
<div className="expense-item__description">
<h2>{props.title}</h2>
</div>
<div className="expense-item__price">${props.amount}</div>
<button onClick={clickHandeler}>Change Title</button>
</Card>
);
};
export default ExpenseItem;