I know the handleChange and handleSubmit are not done but that is not the problem as even with removing those elements I can not get it to load. I am working through an older tutorial and some things are deprecated but I can not figure the problem with this part. Even using code from Github:
https://github.com/CleverProgrammers/react-challenge-amazon-clone/blob/master/src/Payment.js
…that the creators used will not load any better. All other parts load just fine.
Thanks for any insight as this is a learning experience for me.
import { React, useState } from 'react'
import CurrencyFormat from 'react-currency-format';
import { Link } from 'react-router-dom';
import CheckoutProduct from './CheckoutProduct';
import './Payment.css'
import { useStateValue } from './StateProvider'
import { getBasketTotal } from './reducer';
function Payment() {
const [{basket,user},dispatch] =useStateValue();
const [processing , setProcessing] = useState("");
const [succeeded, setSucceeded] = useState(false);
const [error,setError] = useState(null);
const [disabled , setDisabled] = useState(true);
//stripe
const stripe = useStripe();
const elements = useElements();
const handleSubmit = e =>{
//stripe stuff
}
const handleChange = e =>{
//current 600
//lsiten for changes and display errors
setDisabled({error}=null);
setError("Error unknown");// event is depricated need to find valid replacement
}
return (
<div className='payment'>
<div className='payment__container'>
<h1>
Checkout (
<Link to = '/checkout'>{basket?.length} items</Link>
)
</h1>
<div className='payment__section'>
<div className='payment__title'>
<h3>Delivery Adress</h3>
</div>
<div className='payment__address'>
<p>{user?.email}</p>
<p>123 Smith Lane</p>
<p>Camden, New Jersey</p>
</div>
</div>
<div className='payment__section'>
<div className='payment__title'>
<h3>Review Items and delivery</h3>
</div>
<div className='payment__items'>
{basket.map(item =>(
<CheckoutProduct
id ={item.id}
title = {item.title}
image = {item.image}
price = {item.price}
rating = {item.rating}
/>))}
</div>
</div>
<div className='payment__section'>
<div className='payment__title'>
<h3>Payment Title</h3>
</div>
<div className='payment__details'>
{/*Stripe 535*/}
<form onSubmit={handleSubmit}>
<CardElement onChange={handleChange} />
<div className='payment__priceContainer'>
<CurrencyFormat
renderText={(value)=>(
<>
<h3>Order Total: {value}</h3>
</>
)}
decimalScale={2}
value = {getBasketTotal(basket)}
displayType = {"text"}
thousandSeparator = {true}
prefix={'$'}
/>
<button disabled = {processing || disabled || succeeded } >
<span>{processing ? <p>Processing</p>: "Buy Now"}</span>
</button>
</div>
</form>
</div>
</div>
</div>
</div>
)
}
export default Payment
import React, {useState} from 'react';
There's an syntax error in React import
It would be better to post the error you get from browser console. But my guess would be that you have a syntax error somewhere. For example:
<h1>
Checkout (
<Link to = '/checkout'>{basket?.length} items</Link>
)
</h1>
this doesn't look normal.
Related
I would like to know why my "topbar" is duplicated when I only want one. And it's since I did my import of the user image via axios and added the .map in the return. I really don't understand why if someone could help me that would be nice. Thanks in advance
import "./topbar.css"
import { Search } from '#mui/icons-material'
import { useState, useEffect, Fragment } from 'react'
import axios from "axios"
function Home() {
const [user, setPosts] = useState([])
useEffect(() => {
console.log("chargement ok")
const fetchData = async () => {
const result = await axios.get(
'http://localhost:4200/api/user/')
setPosts(result.data)
}
fetchData();
}, [])
return (
<Fragment>
{ user
? user.map((users,topbar) => ( <div key={topbar} className="topBarContainer">
<div className="topBarLeft">
<span className="logo">Groupomania</span>
</div>
<div className="topBarCenter">
<div className="searchBar">
<Search className="searchIcon" />
<input placeholder="Vous cherchez quelque chose ?" className="searchInput" />
</div>
</div>
<div className="topBarRight">
<div className="topBarLinks">
<span className="topBarLink">Page d'acceuil</span>
<span className="topBarLink">Deconnexion</span>
</div>
<img src={users.picture} alt="Photo de profil de l'utilisateur" className="topBarImg" />
</div>
</div>))
: (<p></p>)
}
</Fragment>
)
}
export default Home
I'm not sure why, but it may be because of your key.
Some patterns to fix first:
const [user, setPosts] = useState([]) -> const [posts, setPosts] = useState([])
you don't have to use the word Fragment: -> <>
Normally in a .map params are used like this posts.map((post, index) => ...)
posts ? post.map(...) : null
Edit: of course you have to remove your topbar from your .map(...)
Now try with a better key than "topbard" that is the index in the array ... try post.id that should be uniq
Edit solution:
import "./topbar.css";
import { Search } from "#mui/icons-material";
import { useState, useEffect, Fragment } from "react";
import axios from "axios";
function Home() {
const [user, setUser] = useState();
useEffect(() => {
console.log("chargement ok");
const fetchData = async () => {
const result = await axios.get("http://localhost:4200/api/user/");
setUser(result.data);
};
fetchData();
}, []);
return (
<div className="topBarContainer">
<div className="topBarLeft">
<span className="logo">Groupomania</span>
</div>
<div className="topBarCenter">
<div className="searchBar">
<Search className="searchIcon" />
<input
placeholder="Vous cherchez quelque chose ?"
className="searchInput"
/>
</div>
</div>
<div className="topBarRight">
<div className="topBarLinks">
<span className="topBarLink">Page d'acceuil</span>
<span className="topBarLink">Deconnexion</span>
</div>
{user && <img
src={user.picture}
alt="Photo de profil de l'utilisateur"
className="topBarImg"
/>}
</div>
</div>
);
}
export default Home;
As the map is rendering the topbar for every user, you get as many topbars as there are users.
The map function should be inside the top bar container div.
<div key={key} className="topBarContainer">
{ user.map(...) }
</div>
This is because your are making the topbar inside the loop,So you are getting a topbar per user.
Hey I am learning reactjs as much as i have learned I am trying to make note app
my code given below
my App.js file
import React , {useEffect, useState} from "react"
import { nanoid } from "nanoid"
import Editor from './Note/Editor'
import Sidebar from "./Note/Sidebar"
function App() {
const [notes , setNotes] = useState(JSON.parse(localStorage.getItem("notes"))||[])
const [currentNoteID , setCurrentNoteID] = useState(false)
useEffect(()=>{
localStorage.setItem("notes" , JSON.stringify(notes))
},[notes])
function createNewNotes(){
const newNotes = {
id: nanoid(),
title:"untitled",
body: "sdasda",
lastModified: Date.now()
}
setNotes(prevNote => [newNotes , ...prevNote])
setCurrentNoteID(newNotes.id)
}
function deleteNote(noteID){
setNotes(prevNote => prevNote.filter(note=> note.id !== noteID ))
}
function getNotes(){
return notes.find((note)=> note.id === currentNoteID)
}
return (
<div className="note">
<Sidebar
notes={notes}
createNewNotes={createNewNotes}
currentNoteID={currentNoteID}
setCurrentNoteID={setCurrentNoteID}
deleteNote={deleteNote}
/>
<Editor
notes={getNotes()}
currentNoteID={currentNoteID}/>
</div>
);
}
export default App;
my Sidebar.js file
import React from 'react'
import './style.css'
export default function Sidebar(props){
return(
<>
<div className='sidebar' >
<div className='sidebar-header'>
<h3>Notes</h3>
<button className='add' onClick={props.createNewNotes} >Add</button>
</div>
{ props.notes.map((note)=>{
return(
<div key={note.id}
className={`${note.id===props.currentNoteID ? "active" : ""}`}
onClick={()=>props.setCurrentNoteID(note.id)}
>
<div>
<div className="sidebar-tab">
<div className='sidebar-title'>
<p className='title'>Untitled</p>
<button className='delete' onClick={()=>props.deleteNote(note.id)}>Delete</button>
</div>
<p className='note-preview'>summary of text</p>
</div>
</div>
</div>
)
})}
</div>
</>
)
}
my Editor.js file
import React , {useState} from "react";
import './style.css'
export default function Editor(props){
const [edit , setEdit] = useState(props.notes)
function handleChange(event){
const {name , value} = event.target
setEdit(prevNote=> {
return {
...prevNote,
[name] : value
}
})
}
if(!props.currentNoteID)
return <div className="no-note">no note active</div>
return(
<>
<div className="main">
<input type="text" className="main-input" name="title" placeholder="Enter title here" value={edit.title} onChange={handleChange} autoFocus/>
<textarea className="main-textarea" name="body" placeholder="Type your notes" value={edit.body} onChange={handleChange} />
<div className="preview">
<h1 className="preview-title">{edit.title}</h1>
<div className="main-preview">{edit.body}</div>
</div>
</div>
</>
)
}
whenever i click add button or any sidebar button it shows me error
Uncaught TypeError: Cannot read properties of undefined (reading 'title')
please help me out how to fix this issue
You're expecting getNotes (which should probably be named getActiveNote, IMHO) to re-run every time notes or currentNoteID change.
To achieve this, you have to declare it as a callback (useCallback) and to declare its dependencies. Also you want to place the result in state (e.g: activeNote):
const getActiveNote = useCallback(
() => notes.find((note) => note.id === currentNoteID),
[notes, currentNoteID]
);
const [activeNote, setActiveNote] = useState(getActiveNote());
useEffect(() => {
setActiveNote(getActiveNote());
}, [getActiveNote]);
// ...
<Editor note={activeNote} />
... at which point, you no longer need the currentNoteID in the <Editor /> as you can get it from props.note.id.
See it working here: https://codesandbox.io/s/crazy-glade-qb94qe?file=/src/App.js:1389-1448
Note: the same thing needs to happen in <Editor>, when note changes:
useEffect(() => setEdit(note), [note]);
I just want to show toggled item. But all map items showing up. Basically this is the result I'm getting from onclick. I think i need to give index or id to each item but i don't know how to do it. i gave id to each question didn't work.
App.js.
import "./App.css";
import React, { useState, useEffect } from "react";
import bg from "./images/bg-pattern-desktop.svg";
import bg1 from "./images/illustration-box-desktop.svg";
import bg2 from "./images/illustration-woman-online-desktop.svg";
import { data } from "./data";
import Faq from "./Faq";
function App() {
const [db, setDb] = useState(data);
const [toggle, setToggle] = useState(false);
useEffect(() => {
console.log(db);
}, []);
return (
<>
<div className="container">
<div className="container-md">
<div className="faq">
<img src={bg} className="bg" />
<img src={bg1} className="bg1" />
<img src={bg2} className="bg2" />
<div className="card">
<h1>FAQ</h1>
<div className="info">
{db.map((dat) => (
<Faq
toggle={toggle}
setToggle={setToggle}
title={dat.title}
desc={dat.desc}
key={dat.id}
id={dat.id}
/>
))}
</div>
</div>
</div>
</div>
</div>
</>
);
}
export default App;
(map coming from simple data.js file that I created. it includes just id title desc.)
Faq.js
import React from "react";
import arrow from "./images/icon-arrow-down.svg";
const Faq = ({ toggle, setToggle, title, desc, id }) => {
return (
<>
{" "}
<div className="question" onClick={() => setToggle(!toggle)}>
<p>{title}</p>
<img src={arrow} className={toggle ? "ikon aktif" : "ikon"} />
</div>
<p className="answer border">{toggle ? <>{desc}</> : ""}</p>
</>
);
};
export default Faq;
You need to store the index value of the toggle item.
You can modify the code with only 2 lines with the existing codebase.
import "./App.css";
import React, { useState, useEffect } from "react";
import bg from "./images/bg-pattern-desktop.svg";
import bg1 from "./images/illustration-box-desktop.svg";
import bg2 from "./images/illustration-woman-online-desktop.svg";
import { data } from "./data";
import Faq from "./Faq";
function App() {
const [db, setDb] = useState(data);
const [toggle, setToggle] = useState(-1); //Modify Here
useEffect(() => {
console.log(db);
}, []);
return (
<>
<div className="container">
<div className="container-md">
<div className="faq">
<img src={bg} className="bg" />
<img src={bg1} className="bg1" />
<img src={bg2} className="bg2" />
<div className="card">
<h1>FAQ</h1>
<div className="info">
{db.map((dat, index) => ( //Modify Here
<Faq
toggle={index === toggle} //Modify Here
setToggle={() => setToggle(index)} //Modify Here
title={dat.title}
desc={dat.desc}
key={dat.id}
id={dat.id}
/>
))}
</div>
</div>
</div>
</div>
</div>
</>
);
}
export default App;
import React from "react";
import arrow from "./images/icon-arrow-down.svg";
const Faq = ({ toggle, setToggle, title, desc, id }) => {
return (
<>
{" "}
<div className="question" onClick={setToggle}>
<p>{title}</p>
<img src={arrow} className={toggle ? "ikon aktif" : "ikon"} />
</div>
<p className="answer border">{toggle ? <>{desc}</> : ""}</p>
</>
);
};
export default Faq;
You will need state for each toggle. Here is a minimal verifiable example. Run the code below and click ⭕️ to toggle an item open. Click ❌ to close it.
function App({ faq = [] }) {
const [toggles, setToggles] = React.useState({})
const getToggle = key =>
Boolean(toggles[key])
const setToggle = key => event =>
setToggles({...toggles, [key]: !getToggle(key) })
return faq.map((props, key) =>
<Faq key={key} {...props} open={getToggle(key)} toggle={setToggle(key)} />
)
}
function Faq({ question, answer, open, toggle }) {
return <div>
<p>
{question}
<button onClick={toggle} children={open ? "❌" : "⭕️"} />
</p>
{open && <p>{answer}</p>}
</div>
}
const faq = [
{question: "hello", answer: "world"},
{question: "eat", answer: "vegetables"}
]
ReactDOM.render(<App faq={faq} />, document.querySelector("#app"))
p { border: 1px solid gray; padding: 0.5rem; }
p ~ p { margin-top: -1rem; }
button { float: right; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>
Instead of doing this (in App component):
const [db, setDb] = useState(data);
const [toggle, setToggle] = useState(false);
you can write an useState hook like below to combine the two hooks and assign an isOpened property for each Faq element:
const [db, setDb] = useState(data.map(value=>{return {...value, isOpened:false}}));
and then right here you can do this (as the child of <div className="info">):
{db.map((dat, index) => (
<Faq
toggle={dat.isOpened}
setToggle={() => toggleById(dat.id)}
title={dat.title}
desc={dat.desc}
key={dat.id}
id={dat.id}
/>
))}
Also you need to declare toggleById function in App component:
const toggleById = (id) => {
const newDb = db.map(dat=>{
if(dat.id==id){
return {...dat,isOpened:!dat.isOpened}
}
return dat;
});
setDb(newDb);
}
and since setToggle prop of Faq, calls toggleById by its defined parameter, there is no need to do this in Faq component:
<div className="question" onClick={() => setToggle(!toggle)}>
you can simply write:
<div className="question" onClick={setToggle}>
I have a problem because I try to add place._id to another component as props (line 102), but I need to do it after click on button (line 96 and function editPlace - line 37-41) to display information about place inside popup. However I get totally various id's after refreshing the page I know that it's propably connected with rendering but to be honest I don't know how to do it properly. I've tried to add EditPlaceForm to document but ref's are not my strength yet and also I don't know if it's good strategy.
Numbers of lines are placed in comments.
import React, {
Children,
useContext, useRef, useState,
} from 'react';
import { Link } from 'react-router-dom';
import { removePlace, updatePlaceStatus } from '../../actions/FetchData';
import '../../scss/base/_users-list.scss';
import { PlacesContext } from '../../contexts/PlacesContext';
import EditPlaceForm from './EditPlaceForm/EditPlaceForm';
import '../../scss/base/_places-panel.scss';
function PlacesPanel() {
const places = useContext(PlacesContext);
const popupEl = useRef(null);
const [placeToEdit, setPlaceToEdit] = useState(0);
const handleChangeStatus = (event) => {
const changedStatus = event.target.value;
const changedPlaceId = event.target.id;
updatePlaceStatus(changedPlaceId, changedStatus);
};
const removeSelectedPlace = (event) => {
const removedPlaceId = event.target.value;
const fetchMyData = async () => {
await removePlace(removedPlaceId);
};
fetchMyData();
window.location.reload(true);
};
{/* lines 37-42 here */}
const editPlace = (e, placeId) => {
setPlaceToEdit(placeId);
popupEl.current.style.display = 'block';
console.log(placeId, placeToEdit);
};
return (
<>
<div className="page-container">
<h1>Users list</h1>
{places.map((place) => (
<div className="place-list-item" key={place._id}>
<button className="remove-user-button" value={place._id} type="submit" onClick={removeSelectedPlace}>X</button>
<div>
<Link to={place._id}><img className="place-img" src={place.img} alt="place-img" width="100" height="100" /></Link>
</div>
<div className="place-name">
<h4><Link to={place._id}>{place.name}</Link></h4>
</div>
<div className="place-address">
<h5>
{place.city}
,
{' '}
{place.street}
,
{' '}
{place.houseNo}
,
{' '}
{place.postalCode}
</h5>
</div>
<div className="place-category">
<p>
Kategoria:
{place.category}
</p>
</div>
<div className="place-district">
<p>
Dzielnica:
{place.district}
</p>
</div>
<div className="place-status">
<p>
<b>
Status:
{place.statusPlace}
</b>
</p>
</div>
<p>Zmień status: </p>
<select onChange={handleChangeStatus} id={place._id}>
<option selected value=""> </option>
<option value="pending">pending</option>
<option value="added">added</option>
</select>
{/* line 96 here */}
<input className="edit-place-button" value="Edytuj" onClick={() => editPlace(this, place._id)} type="submit" />
</div>
))}
<div className="popup" ref={popupEl}>
<div className="button-popup-container">
<button type="submit" className="button-popup" onClick={() => { popupEl.current.style.display = 'none'; }}>X</button>
{/* line 102 here */}
<EditPlaceForm placeToEdit={placeToEdit} />
</div>
</div>
</div>
</>
);
}
export default PlacesPanel;
you forgot to change at here, at handleChangeStatus,
setPlaceToEdit(changedPlaceId); adding this will resolve issue,
now after changeing options it will send new values, i hope this is what you are looking for,
const handleChangeStatus = (event) => {
const changedStatus = event.target.value;
const changedPlaceId = event.target.id;
setPlaceToEdit(changedPlaceId);
updatePlaceStatus(changedPlaceId, changedStatus);
};
you can also try to re render using useEffect hook, to ensure latest data changes happened and children rendered, useEffect(()=>{},[placeToEdit, showPop ])
const [placeToEdit, setPlaceToEdit] = useState({});
const [showPop, setShowPop] = useState(false);
useEffect(()=>{},[placeToEdit, showPop ])
const editPlace = (place) => {
setPlaceToEdit(place);
setShowPop(true);
popupEl.current.style.display = 'block';
console.log(placeId, placeToEdit);
};
<input className="edit-place-button" value="Edytuj" onClick={() => editPlace(place)} type="submit" />
then,
{ showPop &&
<div className="popup" ref={popupEl}>
<div className="button-popup-container">
<button type="submit" className="button-popup" onClick={() => { popupEl.current.style.display = 'none'; }}>X</button>
{/* line 102 here */}
<EditPlaceForm placeToEdit={placeToEdit} setShowPop={setShowPop}/>
</div>
</div>
}
So, I made a react app that displays a list of items from a json file as in the pic.
I want to implement a search feature where i can enter the name and it checks for the name in list and scrolls to it.
A person told me about scroll-into-view , but I'm not understand how to make it compare the search term to the names in list.
My App.js code
import React,{useState} from 'react';
import Notes from './Notes';
import './App.css';
function App() {
const [notes] = useState([]);
const handleSubmit= ()=>{
//Upon submitting I want the search functionality to be implemented here . If thats the way to do it.
}
return (
<div className="App">
<div className="App-header">
<form><input type="text" placeholder="Start Typing.." onSubmit={handleSubmit} ></input></form>
<div className="pageTitle">Song Notes :</div>
<Notes thisNotes={notes}/>
</div>
</div>
);
}
export default App;
My Notes.js code:
import React from 'react';
const Notes = ({notes})=>{
const jsonNotes = require('./Notes.json');
const songNotes = jsonNotes.map(note => {
return(
<div key={note.id}>
<li class="noteAsList">
<div className="songTitle">{note.Name}</div>
<pre><br></br>{note.Notes}</pre>
</li>
</div>
)
})
return(
<div className="noteStyle">
{songNotes}
</div>
)
}
export default Notes;
I'm looking to implement such a feature. Either scrolling into view in the page or just displaying the item I asked for.
Thanks for the help in advance.
Codesandbox
My App.js code
import React, { useState } from "react";
import Notes from "./Notes";
import "./App.css";
const jsonNotes = require("./Notes.json");
const App = () => {
const [notes] = useState([]);
const handleSubmit = event => {
if (event.key === "Enter") {
console.log(event.target.value);
const obj = jsonNotes.find(item => item.Name === event.target.value);
const el = document.getElementById(obj.id);
if (el)
el.scrollIntoView({
behavior: "smooth",
block: "start",
inline: "center"
});
}
};
return (
<div className="App">
<div className="App-header">
<input
type="text"
placeholder="Start Typing.."
onKeyPress={handleSubmit}
/>
<div className="pageTitle">Song Notes :</div>
<Notes thisNotes={notes} />
</div>
</div>
);
};
export default App;
My Notes.js code:
import React from "react";
const jsonNotes = require("./Notes.json");
const Notes = ({ notes }) => {
const songNotes = jsonNotes.map(note => {
return (
<div id={note.id} key={note.id}>
<li className="noteAsList">
<div className="songTitle">{note.Name}</div>
<pre>
<br />
{note.Notes}
</pre>
</li>
</div>
);
});
return <div className="noteStyle">{songNotes}</div>;
};
export default Notes;