react update state from children broke component at the same level - javascript

I am new to react. I'm trying to update the parent state from the child but i have an error on another component at the the same level of the child one.
that's my code.
RedirectPage.js (parent)
const RedirectPage = (props) => {
const [status, setStatus] = useState("Loading");
const [weather, setWeather] = useState(null);
const [location, setLocation] = useState(null)
const [showLoader, setShowLoader] = useState(true)
const [userId, setUserId] = useState(false)
const [isPlaylistCreated, setIsPlaylistCreated] = useState(false)
const headers = getParamValues(props.location.hash)
const getWeather = () =>{
//fetch data..
//...
//...
.then(response => {
var res = response.json();
return res;
})
.then(result => {
setWeather(result)
setShowLoader(false)
setStatus(null)
setLocation(result.name)
});
})
}
const changeStateFromChild = (value) => {
setIsPlaylistCreated(value)
}
useEffect(() => {
getWeather()
},[]);
return (
<div className="containerRedirectPage">
{showLoader ? (
<div className="wrapperLogo">
<img src={loader}className="" alt="logo" />
</div>)
: (
<div className="wrapperColonne">
<div className="firstRow">
<WeatherCard weatherConditions={weather}/>
</div>
{isPlaylistCreated ? (
<div className="secondRow">
<PlaylistCard />
</div>
) : (
<PlaylistButton userId={userId} headers={headers} weatherInfo={weather} playlistCreated={changeStateFromChild} />
)}
</div>
)}
</div>
)
};
export default RedirectPage;
PlaylistButton.js:
export default function PlaylistButton({userId, headers, weatherInfo, playlistCreated}) {
const buttonClicked = async () => {
// ...some code...
playlistCreated(true)
}
return (
<div className="button-container-1">
<span className="mas">CREA PLAYLIST</span>
<button onClick={buttonClicked} id='work' type="button" name="Hover">CREA PLAYLIST</button>
</div>
)
}
and that's the other component i'm getting the error when i click on button.
WeatherCard.js:
const WeatherCard = ({weatherConditions}) => {
const [weather, setWeather] = useState(null);
const [icon, setIcon] = useState(null);
const getTheIcon = () => {
// code to get the right icon
}
setIcon(x)
}
useEffect(() => {
getTheIcon()
},[]);
return (
<div className="weatherCard">
<div className="headerCard">
<h2>{weatherConditions.name}</h2>
<h3>{Math.floor(weatherConditions.main.temp)}°C</h3>
</div>
<div className="bodyCard">
<h5>{weatherConditions.weather[0].description}</h5>
<img className="weatherIcon" src={icon} alt="aa" />
</div>
</div>
)
};
export default WeatherCard;
the first time i load the redirect page WeatherCard component is right. When i click the button i get this error:
error
Can someone explain me why ?

What is the effect of the setting playlistCreated(true) ?
Does it affects the weatherCondition object ?
If weatherCondition could be undefined at some point you need to check it before using its properties (name, main.temp, and weather)
Update:
The error clearly state that it cannot read name from weather because it's undefined. You have to check it before using the weather object properties.
if (!weatherConditions) {
return <div>Loading...</div> // or something appropriate.
}
return (
<div className="weatherCard">
<div className="headerCard">
<h2>{weatherConditions.name}</h2>
{weatherConditions.main && <h3>{Math.floor(weatherConditions.main.temp)}°C</h3>}
</div>
<div className="bodyCard">
{weatherConditions.weather &&
{weatherConditions.weather.length > 0 &&
<h5>{weatherConditions.weather[0].description}</h5>}
....
)

Related

React js useState&useEffect array duplicates elements after a change

I am a beginner in react js programming. I'm trying to do the todo project, which is a classic project. When I delete or add an element from the list, the newly formed list appears on the screen by combining with the previous one, I will show it with a picture below. I did not understand the source of the eror so wanted to post it here to get some advices suggestions about why it is happening.Thank you.(I am getting and storing data in firebase firestore database)
Before Adding an element initial array state
After adding an element to the array.
I am using useState for array and using useEffect to get initial data
MainPage.js that contains form and the list components.
const MainPage = () => {
const [isLoading, setLoding] = useState(true);
const [array, setArray] = useState([]);
const sub = async (email) => {
var result = [];
await onSnapshot(doc(db, "users", email), (doc) => {
var data = doc.data().todos;
data.forEach((element) => {
Object.keys(element).map(() => {
result.push(element["title"]);
});
});
setArray(result);
setLoding(false);
});
};
useEffect(() => {
sub(auth.currentUser.email);
}, []);
const onAddToDo = (todoTitle) => {
setArray((prevAray) => {
return [...prevAray, todoTitle];
});
};
const onRemove = (title) => {
setArray((prevAray) => {
return [array.pop(array.indexOf(title))];
});
};
return (
<div>
{isLoading && <h1>Loading</h1>}
{!isLoading && (
<div>
<section>
<NavBar></NavBar>
<ToDoForm passData={onAddToDo} />
</section>
<section>
<CardList removeCards={onRemove} array={array} />
</section>
</div>
)}
</div>
);
};
export default MainPage;
Firebase.js that stores the firebase update methods
export const deleteItem = (title) => {
updateDoc(doc(db, "users", auth.currentUser.email), {
todos: arrayRemove({ title: title }),
});
};
export const addnewTodo = (title) => {
updateDoc(doc(db, "users", auth.currentUser.email), {
todos: arrayUnion({ title: title }),
});
};
TodoForm.js component
const ToDoForm = (props) => {
const [todoTitle, setTitle] = useState("");
const titleChangeHandler = (event) => {
setTitle(event.target.value);
};
const newTodoAdder = (event) => {
event.preventDefault();
addnewTodo(todoTitle);
props.passData(todoTitle);
};
return (
<div className="form_holder">
<div className="form_container">
<form onSubmit={newTodoAdder}>
<h3>Add Events</h3>
<label>Title</label>
<input
onChange={titleChangeHandler}
type="text"
placeholder="Title"
id="title"
></input>
<div className="holder">
<button type="sumbit">Add</button>
</div>
</form>
</div>
</div>
);
};
export default ToDoForm;
CardList.js component
const CardList = (props) => {
const array = props.array;
if (array.length === 0) {
return (
<div className="grid_container">
<h2>Found no todos</h2>
</div>
);
}
return (
<div className="grid_container">
{array.map((element, index) => {
return (
<Card
removeSelf={() => {
props.removeCards(element);
}}
key={index}
title={element}
/>
);
})}
</div>
);
};
export default CardList;
Card.js component
const Card = (props) => {
const handleRemove = (event) => {
event.preventDefault();
deleteItem(props.title);
props.removeSelf();
};
return (
<div className="card">
<h2 className="card__title">{props.title}</h2>
<button type="button" onClick={handleRemove}>
Delete
</button>
</div>
);
};
export default Card;
EDIT ;
Index.js file
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { BrowserRouter } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
SOLUTION
I fixed the issue by changing the add and remove functions that were inside of MainPage.js file You can see the new versions bellow. Hope someday it will help somebody.
Use effect was called once all I had to do get the data again after a change...
New Remove and Add functions
const onAddToDo = (todoTitle) => {
console.log(todoTitle + " Added");
sub(auth.currentUser.email);
};
const onRemove = (title) => {
console.log(title + " Deleted");
sub(auth.currentUser.email);
};

Uncaught TypeError: Cannot read properties of undefined (reading 'longdescription_title') when page is refreshed

I'm pretty new to react, and I am trying to make an Accordion Component with multiple dropdowns. I am trying to load my data from my database. I had thought I got it to work because it showed my data in the correct areas, but when I refreshed the page I got an Uncaught TypeError: Cannot read properties of undefined (reading 'longdescription_title') error. I'm not sure why this is happening, and I would really appreciate any help or advice on how to fix this problem.
Thank you!
import React, { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import { detailsProduct } from '../actions/productActions';
import LoadingBox from '../components/LoadingBox';
import MessageBox from '../components/MessageBox';
import '../components/Accordion.css'
import { IconContext } from 'react-icons';
import { FiPlus, FiMinus } from 'react-icons/fi';
export default function ProductScreen(props) {
const dispatch = useDispatch();
const productId = props.match.params.id;
const [accordionItems, setAccordionItems] = useState([]);
const [accordionTitles, setAccordionTitles] = useState([]);
const [clicked, setClicked] = useState(false);
const productDetails = useSelector((state) => state.productDetails);
const { loading, error, product } = productDetails;
const userSignin = useSelector((state) => state.userSignin);
const { userInfo } = userSignin;
useEffect(() => {
if (product) {
const accordionItems = [product.how_to_use];
accordionItems.unshift(product.ingredients);
accordionItems.unshift(product.longdescription);
setAccordionItems(accordionItems);
}
}, [product]);
useEffect(() => {
if (product) {
const accordionTitles = [product.how_to_use_title];
accordionTitles.unshift(product.ingredients_title);
accordionTitles.unshift(product.longdescription_title);
setAccordionTitles(accordionTitles);
}
}, [product]);
const Items = [...accordionItems];
const Titles = [...accordionTitles];
const accordion = [
{title: product.longdescription_title, body: product.longdescription},
{title: product.ingredients_title, body: product.ingredients},
{title: product.how_to_use_title, body: product.how_to_use},
]
const toggle = index => {
if (clicked === index) {
return setClicked(null);
}
setClicked(index);
};
return (
<div>
{loading ? (
<LoadingBox></LoadingBox>
) : error ? (
<MessageBox variant="danger">{error}</MessageBox>
) : (
<div>
<Link to="/body">Back to result</Link>
<div className="row top">
<div className="col-1">
<ul>
<li>
<h1>{product.name}</h1>
</li>
<li>
<div>
<IconContext.Provider value={{ color: 'black', size: '2vw' }}>
<div className="accordionSection">
<div className = "container">
{accordion && accordion.length ? (
accordion.map((item, index) => {
return (
<>
<div className = "wrap" onClick={() => toggle(index)} key={index}>
<h1>{item.title}</h1>
<span>{clicked === index ? <FiMinus /> : <FiPlus />}</span>
</div>
{clicked === index ? (
<div className="dropdown">
<p>{item.body}</p>
</div>
) :
null}
</>
);
})
) : (
<></>
)}
</div>
</div>
</IconContext.Provider>
</div>
</li>
</ul>
</div>
<li>
<button onClick={addToCartHandler} className="primary block">
Add to Cart
</button>
</li>
</>
)}
</ul>
</div>
</div>
</div>
);
}
Initialize the Items, Titles and accordion variables only when the product has been set (in the useEffect calls).
You should use a separate state to store the accordion array.
Also, no need to use separate useEffect calls:
let Items = [];
let Titles = [];
const [accordion, setAccordion] = useState([]);
useEffect(() => {
if (product) {
const accordionItems = [product.how_to_use];
accordionItems.unshift(product.ingredients);
accordionItems.unshift(product.longdescription);c
setAccordionItems(accordionItems);
Items = [...accordionItems];
const accordionTitles = [product.how_to_use_title];
accordionTitles.unshift(product.ingredients_title);
accordionTitles.unshift(product.longdescription_title);
setAccordionTitles(accordionTitles);
Titles = [...accordionTitles];
setAccordion([
{ title: product.longdescription_title, body: product.longdescription },
{ title: product.ingredients_title, body: product.ingredients },
{ title: product.how_to_use_title, body: product.how_to_use },
]);
}
}, [product]);

How to avoid prop drilling ? / How to use useContext?

I'm working on a React Notes Application and my App.js contains all the necessary functions props which are passed down to several components.
As a result I'm doing prop drilling a lot where I'm passing down around 10-20 props/functions in the components where it isn't needed.
I tried using useContext Hook but I guess it doesn't work with callback functions in the value parameter.
App.js
const App = () => {
const [ notes, setNotes ] = useState([]);
const [ category, setCategory ] = useState(['Notes']);
const [ searchText, setSearchText ] = useState('');
const [ alert, setAlert ] = useState({
show:false,
msg:'',
type:''
});
const [isEditing, setIsEditing] = useState(false);
const [editId, setEditId] = useState(null);
useEffect(()=>{
keepTheme();
})
// retreive saved notes
useEffect(()=>{
const savedNotes = JSON.parse(localStorage.getItem('react-notes-data'));
if (savedNotes) {
setNotes(savedNotes)
}
}, []);
// save notes to local storage
useEffect(() => {
localStorage.setItem('react-notes-data', JSON.stringify(notes))
setNotesCopy([...notes]);
}, [notes]);
// save button will add new note
const addNote = (text) => {
const date = new Date();
const newNote = {
id: nanoid(),
text: text,
date: date.toLocaleDateString(),
category: category,
}
const newNotes = [...notes, newNote]
setNotes(newNotes);
}
const deleteNote = (id) => {
showAlert(true, 'Note deleted', 'warning');
const newNotes = notes.filter(note => note.id !== id);
setNotes(newNotes);
}
// hardcoded values for categories
const allCategories = ['Notes', 'Misc', 'Todo', 'Lecture Notes', 'Recipe'];
// copy notes for filtering through
const [notesCopy, setNotesCopy] = useState([...notes]);
const handleSidebar = (category) => {
setNotesCopy(category==='Notes'?[...notes]:
notes.filter(note=>note.category===category));
}
// function to call alert
const showAlert = (show=false, msg='', type='') => {
setAlert({show, msg, type});
}
return (
<div>
<div className="container">
<Sidebar
allCategories={allCategories}
handleSidebar={handleSidebar}
notesCopy={notesCopy}
key={notes.id}
/>
<Header notes={notes} alert={alert} removeAlert={showAlert} />
<Search handleSearchNote={setSearchText} />
<NotesList
notesCopy={notesCopy.filter(note=>
note.text.toLowerCase().includes(searchText) ||
note.category.toString().toLowerCase().includes(searchText)
)}
handleAddNote={addNote}
deleteNote={deleteNote}
category={category}
setCategory={setCategory}
allCategories={allCategories}
showAlert={showAlert}
notes={notes}
setNotes={setNotes}
editId={editId}
setEditId={setEditId}
isEditing={isEditing}
setIsEditing={setIsEditing}
/>
</div>
</div>
)
}
NotesList.js
const NotesList = (
{ notesCopy, handleAddNote, deleteNote, category, setCategory, showHideClassName, allCategories, showAlert, isEditing, setIsEditing, notes, setNotes, editId, setEditId }
) => {
const [ noteText, setNoteText ] = useState('');
const textareaRef = useRef();
// function to set edit notes
const editItem = (id) => {
const specificItem = notes.find(note=>note.id === id);
setNoteText(specificItem.text);
setIsEditing(true);
setEditId(id);
textareaRef.current.focus();
}
return (
<div key={allCategories} className="notes-list">
{notesCopy.map(note => {
return (
<Note
key={note.id}
{...note}
deleteNote={deleteNote}
category={note.category}
isEditing={isEditing}
editId={editId}
editItem={editItem}
/>)
})}
<AddNote
handleAddNote={handleAddNote}
category={category}
setCategory={setCategory}
showHideClassName={showHideClassName}
allCategories={allCategories}
showAlert={showAlert}
isEditing={isEditing}
setIsEditing={setIsEditing}
notes={notes}
setNotes={setNotes}
editId={editId}
setEditId={setEditId}
noteText={noteText}
setNoteText={setNoteText}
textareaRef={textareaRef}
/>
</div>
)
}
AddNote.js
const AddNote = ({ notes, setNotes, handleAddNote, category, setCategory, showHideClassName, allCategories, showAlert, isEditing, setIsEditing, editId, setEditId, noteText, setNoteText, textareaRef }) => {
const [ show, setShow ] = useState(false);
const [ modalText, setModalText ] = useState('');
const charCount = 200;
const handleChange = (event) => {
if (charCount - event.target.value.length >= 0) {
setNoteText(event.target.value);
}
}
const handleSaveClick = () => {
if (noteText.trim().length === 0) {
setModalText('Text cannot be blank!');
setShow(true);
}
if (category === '') {
setModalText('Please select a label');
setShow(true);
}
if (noteText.trim().length > 0 && category!=='') {
showAlert(true, 'Note added', 'success');
handleAddNote(noteText);
setNoteText('');
setShow(false);
}
if (noteText.trim().length > 0 && category!=='' && isEditing) {
setNotes(notes.map(note=>{
if (note.id === editId) {
return ({...note, text:noteText, category:category})
}
return note
}));
setEditId(null);
setIsEditing(false);
showAlert(true, 'Note Changed', 'success');
}
}
const handleCategory = ( event ) => {
let { value } = event.target;
setCategory(value);
}
showHideClassName = show ? "modal display-block" : "modal display-none";
return (
<div className="note new">
<textarea
cols="10"
rows="8"
className='placeholder-dark'
placeholder="Type to add a note.."
onChange={handleChange}
value={noteText}
autoFocus
ref={textareaRef}
>
</textarea>
<div className="note-footer">
<small
className='remaining'
style={{color:(charCount - noteText.length == 0) && '#c60000'}}>
{charCount - noteText.length} remaining</small>
<div className='select'>
<select
name={category}
className="select"
onChange={(e)=>handleCategory(e)}
required
title='Select a label for your note'
defaultValue="Notes"
>
<option value="Notes" disabled selected>Categories</option>
{allCategories.map(item => {
return <option key={item} value={item}>{item}</option>
})}
</select>
</div>
<button className='save' onClick={handleSaveClick} title='Save note'>
<h4>{isEditing ? 'Edit':'Save'}</h4>
</button>
</div>
{/* Modal */}
<main>
<div className={showHideClassName}>
<section className="modal-main">
<p className='modal-text'>{modalText}</p>
<button type="button" className='modal-close-btn'
onClick={()=>setShow(false)}><p>Close</p>
</button>
</section>
</div>
</main>
</div>
)
}
I want the functions passed from App.js to NotesList.js to be in AddNote.js without them being passed in NotesList.js basically minimizing the props destructuring in NotesList.js
Context API does work with function. What you need to do is pass your function to Provider inside value :
<MyContext.Provider value={{notes: notesData, handler: myFunction}} >
For example:
// notes-context.js
import React, { useContext, createContext } from 'react';
const Context = createContext({});
export const NotesProvider = ({children}) => {
const [notes, setNote] = useState([]);
const addNote = setNote(...); // your logic
const removeNote = setNote(...); // your logic
return (
<Context.Provider value={{notes, addNote, removeNote}}>
{children}
</Context.Provider>
)
}
export const useNotes = () => useContext(Context);
Add Provider to your App.js like so:
// App.js
import NoteProvider from './notes-context';
export default App = () => {
return (
<NoteProvider>
<div>... Your App</div>
</NoteProvider>
)
}
Then call UseNote in your NoteList.js to use the function:
// NoteList.js
import {useNotes} from './note-context.js';
export const NoteList = () => {
const {notes, addNotes, removeNotes} = useNotes();
// do your stuff. You can now use functions addNotes and removeNotes without passing them down the props
}

How to use spinner and then display a component after submit button?

So I am building this project using ChakraUI and ReactJS.
So in this UploadImage component, what I wanna do is, when you choose a file and then hit the Upload button, the spinner will load while the data is being fetched. After it is finished fetching the data, the loading is going to be false and it will render the component.
But currently it is rendering component initially and after you submit the file it renders the DisplayImage component.
So how to implement the spinner component properly?
My current code is the following:
function UploadImage() {
const [selectedFile, setSelectedFile] = useState(null);
const [error, setError] = useState(null);
const [inputImage, setInputImage] = useState(null);
const [outputImage, setOutputImage] = useState(null);
const [isSubmit, setIsubmit] = useState(false);
const [isLoading, setIsloading] = useState(true);
const fileUploadHandler = () => {
const fd = new FormData();
fd.append("file", selectedFile, selectedFile.name);
axios
.post(`/api/predict`, fd)
.then((res) => {
setIsubmit(true);
setInputImage(res.data.image);
setOutputImage(res.data.mask);
selectedFile(null);
setError(null);
setIsloading(false);
})
.catch((error) => {
console.log(error);
setSelectedFile(null);
setError(error.data);
});
};
const fileData = () => {
if (selectedFile) {
if (
selectedFile.type === "image/jpeg" ||
selectedFile.type === "image/png"
) {
return (
<div>
{error && <div>file too large!!</div>}
<Button
colorScheme='teal'
size='sm'
onClick={() => fileUploadHandler()}
>
Upload!
</Button>
</div>
);
} else {
return (
<div>
<h4>Please choose an image to upload</h4>
</div>
);
}
} else {
return (
<div>
<h4>Choose Photos</h4>
</div>
);
}
};
return (
<div>
<input type='file' onChange={(e) => setSelectedFile(e.target.files[0])} />
{fileData()}
{isSubmit && isLoading === false ? (
<DisplayImage inputImage={inputImage} outputImage={outputImage} />
) : (
<Spinner />
)}
</div>
);
}
export default UploadImage;
Try this:
function UploadImage() {
const [selectedFile, setSelectedFile] = useState(null);
const [error, setError] = useState(null);
const [inputImage, setInputImage] = useState(null);
const [outputImage, setOutputImage] = useState(null);
const [isLoading, setIsloading] = useState(false);
const fileUploadHandler = () => {
setIsloading(true);
const fd = new FormData();
fd.append("file", selectedFile, selectedFile.name);
axios
.post(`/api/predict`, fd)
.then((res) => {
setInputImage(res.data.image);
setOutputImage(res.data.mask);
selectedFile(null);
setError(null);
setIsloading(false);
})
.catch((error) => {
console.log(error);
setSelectedFile(null);
setError(error.data);
setIsloading(false);
});
};
const fileData = () => {
if (selectedFile) {
if (
selectedFile.type === "image/jpeg" ||
selectedFile.type === "image/png"
) {
return (
<div>
{
error ? <div>file too large!!</div> :
<Button
colorScheme='teal'
size='sm'
onClick={() => fileUploadHandler()}
>
Upload!
</Button>
}
</div>
);
} else {
return (
<div>
<h4>Please choose an image to upload</h4>
</div>
);
}
} else {
return (
<div>
<h4>Choose Photos</h4>
</div>
);
}
};
return (
<div>
<input type='file' onChange={(e) => setSelectedFile(e.target.files[0])} />
{fileData()}
{
isLoading ?
<Spinner /> :
<DisplayImage inputImage={inputImage} outputImage={outputImage} />
}
</div>
);
}
export default UploadImage;

Issue Removing specific React jsx element from list of elements

first time asking questions haha, I'm trying to remove a specific JSX element from my array of elements but I am not sure how to identify said element is the one being clicked to get removed so I wanted to know if anyone encountered this issue before and how you would go about solving it.
This is the code for the input Container
const InputComponent = (props) => {
return (
<div className="input-container" onClick={e =>console.log(e)}>
<input className="input-name" type="text" />
<input className="input-value" type="text" />
<button className="remove-button" onClick={props.remove}><img src={minusIcon} alt="remove-icon" /></button>
</div>
);
}
export default InputComponent;
and this is the code for the parent component to manage the removal of said element
const Main = () => {
const [newInput, setInput] = useState([]);
const [currentInput, setCurrentInput] = useState([<InputComponent key={0}/>]);
const [currentIndex, setIndex] = useState(0)
const [currentPlanName, setCurrentPlanName] = useState('Current-Plan');
const [newPlanName, setNewPlanName] = useState('New-Plan');
// const [currentInputValue, setCurrentValue] = useState('')
// const [newInputValue, setNewValue] = useState('')
// Sets Keys for each New Element in Array
const [newKey, setNewKey] = useState(0);
const [currentKey, setCurrentKey] = useState(0)
// Handle Removal of specific array by using key
const handleCurrentRemoval = () => {
let newArray = currentInput.filter(element => element.key !== )
console.log(newArray)
setCurrentInput(newArray)
}
// Initialize Keys for each Array
const currentArrayElement = {
element: <InputComponent key={currentKey} remove={handleCurrentRemoval} />,
index: currentKey
};
const newArrayElement = <InputComponent key={newKey+1}/>
// Adds new Element to array
const handleCurrentClick = () => {
setCurrentInput(prevValues => [...prevValues, currentArrayElement.element])
setCurrentKey(currentKey+1);
console.log(currentArrayElement)
console.log(currentInput)
};
const handleNewClick = () => {
setInput(prevValues => [...prevValues, newArrayElement])
};
// const handleRemoveClick = (value) => {
// currentInput.filter(current => value !=)
// }
return (
<div className="main-container">
<div className="quote-container">
<div className="current-plan">
<h2>{currentPlanName}</h2>
{
currentInput.map((inputs) => {
return inputs
})
}
<div className="button-container">
<button className="add-input" onClick={handleCurrentClick}><img src={addIcon} alt="add"/></button>
</div>
</div>
<div className="new-plan">
<h2>{newPlanName}</h2>
{
newInput.map((inputs) => {
return inputs
})
}
<div className="button-container">
<button className="add-input" onClick={handleNewClick}><img src={addIcon} alt="add"/></button>
</div>
</div>
</div>
</div>
);
}
export default Main;
I do apologize in advance if I posted this incorrectly.
Thank you for your assistance
I think you've made this entirely more complex than it needs to be with all the index value storage in state. It is also anti-pattern in React to store JSX in state, you should store data in state and render the data to JSX.
I suggest storing generated input ids in the arrays instead and mapping these to JSX.
Example:
// id generator
let id = 0;
const getId = () => id++;
export default function App() {
const [newInput, setInput] = useState([]);
const [currentInput, setCurrentInput] = useState([]);
const [currentPlanName, setCurrentPlanName] = useState("Current-Plan");
const [newPlanName, setNewPlanName] = useState("New-Plan");
// Handle Removal of specific element by using id
const handleCurrentRemoval = (removeId) => {
setCurrentInput((ids) => ids.filter((id) => id !== removeId));
};
// Adds new id to array
const handleCurrentClick = () => {
setCurrentInput((ids) => ids.concat(getId()));
};
const handleNewClick = () => {
setInput((ids) => ids.concat(getId()));
};
const handleRemoveClick = (removeId) => {
setInput((ids) => ids.filter((id) => id !== removeId));
};
return (
<div className="main-container">
<div className="quote-container">
<div className="current-plan">
<h2>{currentPlanName}</h2>
{currentInput.map((id) => {
return (
<InputComponent
key={id}
remove={() => handleCurrentRemoval(id)}
/>
);
})}
<div className="button-container">
<button className="add-input" onClick={handleCurrentClick}>
<img src={addIcon} alt="add" />
</button>
</div>
</div>
<div className="new-plan">
<h2>{newPlanName}</h2>
{newInput.map((id) => {
return (
<InputComponent key={id} remove={() => handleRemoveClick(id)} />
);
})}
<div className="button-container">
<button className="add-input" onClick={handleNewClick}>
<img src={addIcon} alt="add" />
</button>
</div>
</div>
</div>
</div>
);
}

Categories

Resources