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>
}
Related
import React, { useState, useEffect } from 'react'
import { Link } from 'react-router-dom'
import moment from 'moment'
import Avatar from '../../components/Avatar/Avatar'
import { useSelector, useDispatch} from 'react-redux'
import { useParams } from 'react-router-dom'
import { deleteAnswer } from '../../actions/question'
const DisplayAnswer = ( { question, handleShare } ) => {
const User = useSelector((state) => (state.currentUserReducer))
const dispatch = useDispatch()
const { id } = useParams()
const [button, setButton] = useState(false);
const handleDelete = (answerId, noOfAnswers) => {
dispatch(deleteAnswer(id, answerId, noOfAnswers-1))
}
const handleComment = (e) => {
setButton(!button)
alert(e.target.id)
}
return (
<div>
{
question.answer.map( (ans) => (
<div className="display-ans" key={ans._id}>
<p>{ans.answerBody}</p>
<div className="question-actions-user">
<div>
<button type="button" onClick={handleShare}>Share</button>
{
User?.result?._id === ans?.userId && (
<button type='button' onClick={ () => handleDelete(ans._id, question.noOfAnswers) }>Delete</button>
)
}
<div>
</div>
<button id = {ans._id} type='button' onClick = { (e) => handleComment(e) }> Add Comment </button>
{
button &&
(
<div id = {ans._id}>
<textarea rows='5' cols='30'> </textarea> <br />
<button type='button'> Post </button>
</div>
)
}
</div>
<div>
<p>answered { moment(ans.answeredOn).fromNow()}</p>
<Link to={`/Users/${ans.userId}`} className='user-link' style={{color:'#0086d8'}}>
<Avatar backgroundColor="lightgreen" px='8px' py='5px' borderRadius='4px'>{ans.userAnswered.charAt(0).toUpperCase()}</Avatar>
<div>
{ans.userAnswered}
</div>
</Link>
</div>
</div>
</div>
))
}
</div>
)
}
export default DisplayAnswer
I want to add a comment part under every answer
to do that i added a " Add Comment " button under every Answer and i have a button click on that button
and what i want is whenever the button is clicked the addcomment (textbox) should be added under it
but when i click the button the addcomment (textbox) is getting added under every answer
like if 10 answers are their then Addcommment box is getting added under every 10 answers
Currently there is only a single button state that all the mapped answers render a button for. A simple solution would be to instead store the answer id of the answer you want to add a comment for.
Example:
const DisplayAnswer = ({ question, handleShare }) => {
...
const [commentId, setCommentId] = useState(null); // <-- initially null
...
const handleComment = (e) => {
setCommentId(e.target.id); // <-- set answer id here
alert(e.target.id);
};
return (
<div>
{question.answer.map((ans) => (
<div className="display-ans" key={ans._id}>
<p>{ans.answerBody}</p>
<div className="question-actions-user">
<div>
...
<button
id={ans._id}
type="button"
onClick={handleComment}
>
Add Comment
</button>
{commentId === and._id && ( // <-- conditionally render match by id
<div id={ans._id}>
<textarea rows="5" cols="30" />
<br />
<button type="button">Post</button>
</div>
)}
</div>
...
</div>
</div>
))}
</div>
);
};
When the "Post comment" button is clicked and the entered comment is handled don't forget to also set the commentId value back to null to conditionally hide the input.
Each answer must have his own 'state' to display his own textArea, so you have to extract the code of the 'answer' in a new Answer component, and render a new component in the map method.
Each Answer will thus use a "useState" with a "[isTextAreaVisible, setIsTextAreaVisible] = useState(false);" state.
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.
so I currently have a header component in my react js website and I want to set the title of it to an element of an array, but I cant seem to figure out how. here is my code
import Header from './components/Header';
var shoppinglist = []
var currentitem = ""
const App = () => {
function getData(val){
console.warn(val.target.value)
currentitem = val.target.value;
}
function logData() {
shoppinglist.push(currentitem)
console.log(shoppinglist)
}
function deleteItem() {
shoppinglist.pop()
console.log(shoppinglist)
console.log(shoppinglist[0])
}
return (
<div className="Container">
<Header title = "grocery list" />
<input type="text" onChange={getData}></input>
<button onClick={logData}>add item to list</button>
<button onClick={deleteItem}>delete item</button>
<div className="listItems">
<Header title = {shoppinglist[0]} />
</div>
</div>
);
}
export default App;
how would i set the header title to shoppinglist[0]?
You have to have React state in order to render your content - in your case title.
You can read more in react.js
One way of achieving what you asked in question: https://codesandbox.io/s/competent-wildflower-uvusd?file=/App.js
import "./styles.css";
import React from "react";
export default function App() {
const [title, setTitle] = React.useState(null);
const [input, setInput] = React.useState(null);
function getData(val) {
console.warn(val.target.value);
setInput(val.target.value);
}
function deleteItem() {
setTitle(null);
}
return (
<div className="Container">
<input type="text" onChange={getData}></input>
<button onClick={() => setTitle(input)}>add item to list</button>
<button onClick={deleteItem}>delete item</button>
{title && (
<div>
<p>{title}</p>
</div>
)}
</div>
);
}
If you want a dynamic component in react you have to use state-variables. Else React doesn't re-render your code. This could look like this with React Hooks:
import Header from './components/Header';
var currentitem = ""
const App = () => {
const [shoppinglist, setShoppinglist] = useState([]);
function getData(val){
console.warn(val.target.value)
currentitem = val.target.value;
}
function addItem() {
shoppinglist.push(currentitem)
setShoppinglist([...shoppinglist])
}
function deleteItem() {
shoppinglist.pop()
setShoppinglist([...shoppinglist])
}
return (
<div className="Container">
<Header title = "grocery list" />
<input type="text" onChange={getData}></input>
<button onClick={addItem}>add item to list</button>
<button onClick={deleteItem}>delete item</button>
<div className="listItems">
<Header title = {shoppinglist[0]} />
</div>
</div>
);
}
export default App;
I am currently making a project over the database I created using Mock API. I created a button, created addToFavorites function. When the button was clicked, I wanted the selected product's information to go to the favorites, but I couldn't. I would be glad if you could help me on how to do this.
(Favorites.js empty now. I got angry and deleted all the codes because I couldn't.)
(
Recipes.js
import React, { useState, useEffect } from "react"
import axios from "axios"
import "./_recipe.scss"
import Card from "../Card"
function Recipes() {
const [recipes, setRecipes] = useState([])
const [favorites, setFavorites] = useState([])
useEffect(() => {
axios
.get("https://5fccb170603c0c0016487102.mockapi.io/api/recipes")
.then((res) => {
setRecipes(res.data)
})
.catch((err) => {
console.log(err)
})
}, [])
const addToFavorites = (recipes) => {
setFavorites([...favorites, recipes])
console.log("its work?")
}
return (
<div className="recipe">
<Card recipes={recipes} addToFavorites={addToFavorites} />
</div>
)
}
export default Recipes
Card.js
import React, { useState } from "react"
import { Link } from "react-router-dom"
import { BsClock, BsBook, BsPerson } from "react-icons/bs"
function Card({ recipes, addToFavorites }) {
const [searchTerm, setSearchTerm] = useState("")
return (
<>
<div className="recipe__search">
<input
type="text"
onChange={(event) => {
setSearchTerm(event.target.value)
}}
/>
</div>
<div className="recipe__list">
{recipes
.filter((recipes) => {
if (searchTerm === "") {
return recipes
} else if (
recipes.title.toLowerCase().includes(searchTerm.toLowerCase())
) {
return recipes
}
})
.map((recipe) => {
return (
<div key={recipe.id} className="recipe__card">
<img src={recipe.image} alt="foods" width={350} height={230} />
<h1 className="recipe__card__title">{recipe.title}</h1>
<h3 className="recipe__card__info">
<p className="recipe__card__info--icon">
<BsClock /> {recipe.time} <BsBook />{" "}
{recipe.ingredientsCount} <BsPerson />
{recipe.servings}
</p>
</h3>
<h3 className="recipe__card__desc">
{recipe.description.length < 100
? `${recipe.description}`
: `${recipe.description.substring(0, 120)}...`}
</h3>
<button type="button" className="recipe__card__cta">
<Link
to={{
pathname: `/recipes/${recipe.id}`,
state: { recipe }
}}
>
View Recipes
</Link>
</button>
<button onClick={() => addToFavorites(recipes)}>
Add to favorites
</button>
</div>
)
})}
</div>
</>
)
}
export default Card
Final Output:
I have implemented the addToFavorite() and removeFavorite() functionality, you can reuse it the way you want.
I have to do bit of modification to the code to demonstrate its working, but underlying functionality of addToFavorite() and removeFavotie() works exactly the way it should:
Here is the Card.js where these both functions are implemented:
import React, { useState } from "react";
import { BsClock, BsBook, BsPerson } from "react-icons/bs";
function Card({ recipes }) {
const [searchTerm, setSearchTerm] = useState("");
const [favorite, setFavorite] = useState([]); // <= this state holds the id's of all favorite reciepies
// following function handles the operation of adding fav recipes's id's
const addToFavorite = id => {
if (!favorite.includes(id)) setFavorite(favorite.concat(id));
console.log(id);
};
// this one does the exact opposite, it removes the favorite recipe id's
const removeFavorite = id => {
let index = favorite.indexOf(id);
console.log(index);
let temp = [...favorite.slice(0, index), ...favorite.slice(index + 1)];
setFavorite(temp);
};
// this variable holds the list of favorite recipes, we will use it to render all the fav ecipes
let findfavorite = recipes.filter(recipe => favorite.includes(recipe.id));
// filtered list of recipes
let filtered = recipes.filter(recipe => {
if (searchTerm === "") {
return recipe;
} else if (recipe.title.toLowerCase().includes(searchTerm.toLowerCase())) {
return recipe;
}
});
return (
<div className="main">
<div className="recipe__search">
<input
type="text"
onChange={event => {
setSearchTerm(event.target.value);
}}
/>
</div>
<div className="recipe-container">
<div className="recipe__list">
<h2>all recipes</h2>
{filtered.map(recipe => {
return (
<div key={recipe.id} className="recipe__card">
<img src={recipe.image} alt="foods" width={50} height={50} />
<h2 className="recipe__card__title">{recipe.title}</h2>
<h4 className="recipe__card__info">
<p>
<BsClock /> {recipe.time} <BsBook />{" "}
{recipe.ingredientsCount} <BsPerson />
{recipe.servings}
</p>
</h4>
<h4 className="recipe__card__desc">
{recipe.description.length < 100
? `${recipe.description}`
: `${recipe.description.substring(0, 120)}...`}
</h4>
<button onClick={() => addToFavorite(recipe.id)}>
add to favorite
</button>
</div>
);
})}
</div>
<div className="favorite__list">
<h2>favorite recipes</h2>
{findfavorite.map(recipe => {
return (
<div key={recipe.id} className="recipe__card">
<img src={recipe.image} alt="foods" width={50} height={50} />
<h2 className="recipe__card__title">{recipe.title}</h2>
<h4 className="recipe__card__info">
<p className="recipe__card__info--icon">
<BsClock /> {recipe.time} <BsBook />{" "}
{recipe.ingredientsCount} <BsPerson />
{recipe.servings}
</p>
</h4>
<h4 className="recipe__card__desc">
{recipe.description.length < 100
? `${recipe.description}`
: `${recipe.description.substring(0, 120)}...`}
</h4>
<button onClick={() => removeFavorite(recipe.id)}>
remove favorite
</button>
</div>
);
})}
</div>
</div>
</div>
);
}
export default Card;
Here is the live working app : stackblitz
You can get the previous favourites recipes and add the new ones.
const addToFavorites = (recipes) => {
setFavorites(prevFavourites => [...prevFavourites, recipes])
console.log("its work?")
}
I am creating a challenge tracking app in React. I would like to, after clicking on the challenge button and approving it, be able to add it and save it to the local storage (as a value to save the name of the chosen challenge) and later to print it in the dashboard.
Could anyone please help me with that.
I have 3 classes I am working now and will paste them below.
ChooseChallenge.js
function Challange() {
const [isPopped, setPop] = useState(false);
const pop = () => {
setPop(!isPopped);
};
return (
//Fragments
<>
{isPopped && <Dialog />}
<div className="chooseChallenge">
{/* <Leaf/> */}
<h1 className="newchallenge">New Challange</h1>
<hr />
<div className="challanges">
<button className="challangeBtn" onClick={pop}>
Eat Vegetarian (31days)
</button>
<button className="challangeBtn" onClick={pop}>
Take the bike to work (14days)
</button>
<button className="challangeBtn" onClick={pop}>
Recycle your plastic bottles (31days)
</button>
<button className="challangeBtn" onClick={pop} >
Use public transport to commute (31days)
</button>
<button className="challangeBtn" onClick={pop}>
Don't fly an airplane (365days)
</button>
</div>
<br />
</div>
</>
);
}
export default Challange;
Dialog.js
function Dialog (){
const [isOpen, setOpennes] = useState(true);
const Close = () => {
setOpennes(false);
}
const [value, setValue] = React.useState(
localStorage.getItem('challengeName') || ''
);
React.useEffect(() => {
localStorage.setItem('challengeName', value);
}, [value]);
const onChange = event => setValue(event.target.value);
return(
<div className={isOpen ? 'dialogBox' : 'dialogHide'}>
<h3 id="header">Do you accept the challange?</h3>
<div className="approvalButtons">
<button className= "approvalButton" onClick = {Close} value={value} onChange={onChange}> Approve </button>
<button className= "approvalButton" onClick = {Close}> Decline </button>
</div>
</div>
)
}
export default Dialog;
Dashboard.js
export default function Dashboard() {
// const challengelist = document.querySelector('#challange-list')
const [challs, setChalls] = useState([]);
useEffect(() => {
const fetchData = async () => {
var challs = [];
await database
.collection("Challenges")
.get()
.then((snapshot) => {
snapshot.docs.forEach((doc) => {
challs.push(doc.data().ChallengeName);
});
});
setChalls(challs);
};
fetchData();
}, []);
return (
<div className="Dashboard">
<Header />
<div className="circle">
<img id="leafpicture" src={leafpic} alt="eco-picture" />
<div className="textIn">
<h1> You saved </h1>
<h5>0.00 CO2</h5>
</div>
</div>
<div>
<ul id="challange-list">
{challs.map((ch) => (
<li key={ch}>{ch}</li>
))}
</ul>
</div>
<div className="progressbar">
<h3>Track your challenges!</h3>
{testData.map((item, idx) => (
<ProgressBar
key={idx}
bgcolor={item.bgcolor}
completed={item.completed}
/>
))}
</div>
<br />
</div>
);
}
on dialog.js the value of the button starts with an empty string and this value never changes, so you are always storing and empty string.