I'm making a recipe box App, and I decided to start by my handleTitle and handleInput methods. I was able to pull that out, but now I want to make an array of objects (the objects contain the title and the description) and then I would map through this array and display the data.
but my handleSubmit function is not working the way I wanted. I want the user to be able to write several titles and descriptions, and those will keep being added to the recipes array in the state. Take a look at the code:
import React, { useState } from "react";
import "./styles.css";
import { Form } from "./components/containers/Form";
export default function App() {
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
const [recipe, setRecipe] = useState([]);
const handleTitle = e => {
setTitle(e.target.value);
};
const handleDescription = e => {
setDescription(e.target.value);
};
const handleSubmit = e => {
e.preventDefault();
if (title !== "" && description !== "") {
setRecipe(prevState => {
const data = { title: title, description: description };
return {
...prevState,
recipe: prevState.recipe.concat(data)
};
});
}
};
return (
<div className="App">
<Form
title={title}
description={description}
handleTitle={handleTitle}
handleDescription={handleDescription}
handleSubmit={handleSubmit}
/>
</div>
);
}
import React from "react";
export const Form = ({
handleTitle,
handleDescription,
handleSubmit,
title,
description
}) => {
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
onChange={handleTitle}
placeholder="title"
value={title}
/>
<input
type="text"
onChange={handleDescription}
placeholder="description"
value={description}
/>
<button>Add</button>
</form>
</div>
);
};
When you set the recipes, you're changing the primitive type of recipes state to an object. Instead you should just return a new array with the previous recipes and the new recipe.
I've attached a runnable example below:
const Form = ({
handleTitle,
handleDescription,
handleSubmit,
title,
description
}) => {
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
onChange={handleTitle}
placeholder="title"
value={title}
/>
<input
type="text"
onChange={handleDescription}
placeholder="description"
value={description}
/>
<button>Add</button>
</form>
</div>
);
};
function App() {
const [title, setTitle] = React.useState("");
const [description, setDescription] = React.useState("");
const [recipes, setRecipes] = React.useState([]);
const handleTitle = e => {
setTitle(e.target.value);
};
const handleDescription = e => {
setDescription(e.target.value);
};
const handleSubmit = e => {
e.preventDefault();
if (title !== "" && description !== "") {
setRecipes(prevState => {
const data = { title: title, description: description };
return [...prevState, data];
});
setTitle("");
setDescription("");
}
};
return (
<div className="App">
<Form
title={title}
description={description}
handleTitle={handleTitle}
handleDescription={handleDescription}
handleSubmit={handleSubmit}
/>
<h5>Recipes</h5>
{recipes.length === 0
? (
<div>No recipes</div>
)
: (
<ul>
{recipes.map(({ title, description }) => (
<li>
{title} : {description}
</li>
))}
</ul>
)}
</div>
);
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Related
I want to pass the states into a object, because after I'll post an API. How can I store the states into the object? If I call the function setAll() causes a infinite loop.
Like an example the console.log returns infinite times in the console.
import React,{useState} from 'react';
import Signup1 from '../pages/Signup/steps/Signup1';
import Signup2 from '../pages/Signup/steps/Signup2';
import Signup3 from '../pages/Signup/steps/Signup3';
function Forms() {
const [alert,setAlert]=useState();
const [page,setPage] = useState(0);
const [formData,setFormData]= useState({
email :"",
FirstName:"",
LastName:"",
CountryNumber:"",
Number:"",
JobTitle:"",
People:"",
Company:"",
TaxID:""
})
const [email,setEmail] = useState("");
const [firstName,setFirstName] = useState("");
const [lastName,setLastName] = useState("");
const [countryNumber,setCountryNumber] = useState("");
const [number,setNumber] = useState("");
const [jobTitle,setJobTitle] = useState("");
const [people,setPeople] = useState("");
const [company,setCompany] = useState("");
const [taxID,setTaxID] = useState("");
const setAll = ()=>{
setFormData({
email :email,
FirstName:firstName,
LastName:lastName,
CountryNumber:countryNumber,
Number:number,
JobTitle:jobTitle,
People:people,
Company:company,
TaxID:taxID
})
console.log(formData)
}
const PageDisplay = () =>{
if(page===0){
return <Signup1
email={email}
setEmail={setEmail}
setPage={setPage}
/>;
}
if(page===1){
return <Signup2
firstName={firstName}
setFirstName={setFirstName}
lastName={lastName}
setLastName={setLastName}
countryNumber={countryNumber}
setCountryNumber={setCountryNumber}
number={number}
setNumber={setNumber}
jobTitle={jobTitle}
setJobTitle={setJobTitle}
setPage={setPage}/>;
}
if(page===2){
return <Signup3
people={people}
setPeople={setPeople}
company={company}
setCompany={setCompany}
taxID={taxID}
setTaxID={setTaxID}
page={page}
setPage={setPage}
/>
}
if(page===3){
return( <div>sucess</div>)
}
}
/*
if(page===3){
setAll()
return<div>sucess</div>
}
*/
return (
<div className='Forms'>
{PageDisplay()}
</div>
);
}
export default Forms;
Don't call setAll() like this, functions that set state like this should be called on the occurrence of an event (like an onClick) or in a useEffect, whenever you set a state in the component body, the component re-renders which triggers another state set, thus causing an infinite loop, in your case, it's better to set the form body when you call the API. Setting states is a costly operation, so it's better to set form body state finally when you are going to hit the API.
Making a working example always helps someone to create a better and more precise answer to your question. This is how you set your data.
Also if you want to send this data to another component/function you can do it by passing formData object, you don't need to set it one by one.
Please try to ask any questions you may have.
To see the document clearly, expand the snippet to fill the entire page.
const {useEffect, useState} = React;
const Forms = () => {
const [alert,setAlert]=useState();
const [page,setPage] = useState(0);
const [formData,setFormData]= useState({
email :"",
FirstName:"",
LastName:"",
CountryNumber:"",
Number:"",
JobTitle:"",
People:"",
Company:"",
TaxID:""
})
const [email,setEmail] = useState("");
const [firstName,setFirstName] = useState("");
const [lastName,setLastName] = useState("");
const [countryNumber,setCountryNumber] = useState("");
const [number,setNumber] = useState("");
const [jobTitle,setJobTitle] = useState("");
const [people,setPeople] = useState("");
const [company,setCompany] = useState("");
const [taxID,setTaxID] = useState("");
useEffect(() => {
console.log(formData);
}, [formData]);
useEffect(() => {
setAll();
}, [email, firstName, lastName, countryNumber, number, jobTitle, people, company, taxID]);
const setAll = () => {
setFormData({
email :email,
FirstName:firstName,
LastName:lastName,
CountryNumber:countryNumber,
Number:number,
JobTitle:jobTitle,
People:people,
Company:company,
TaxID:taxID
})
}
const Signup2 = ({data}) => {
return <div>Email: {data.email}</div>;
}
const Signup3 = ({data}) => {
return "Signup3 Page Content";
}
const PageDisplay = () =>{
if(page===0){
return <form>
<input onChange={(e) => setEmail(e.target.value)} value={email} type="text" />
<input onChange={(e) => setFirstName(e.target.value)} value={firstName} type="text" />
<input onChange={(e) => setLastName(e.target.value)} value={lastName} type="text" />
<input onChange={(e) => setCountryNumber(e.target.value)} value={countryNumber} type="text" />
<input onChange={(e) => setNumber(e.target.value)} value={number} type="text" />
<input onChange={(e) => setJobTitle(e.target.value)} value={jobTitle} type="text" />
<input onChange={(e) => setPeople(e.target.value)} value={people} type="text" />
<input onChange={(e) => setCompany(e.target.value)} value={company} type="text" />
<input onChange={(e) => setTaxID(e.target.value)} value={taxID} type="text" />
</form>;
}
if(page===1){
return <Signup2 data={formData} />;
}
if(page===2){
return <Signup3 data={formData} />
}
if(page===3){
return( <div>sucess</div>)
}
}
return (
<div>
<button onClick={() => setAll()}>Trigger SetAll</button>
<div>Current Page {page + 1}</div>
<button onClick={() => setPage(0)}>Page 1</button>
<button onClick={() => setPage(1)}>Page 2</button>
<button onClick={() => setPage(2)}>Page 3</button>
<div>{PageDisplay()}</div>
</div>
);
};
ReactDOM.render(
<Forms />,
document.getElementById("root")
);
input[type="text"]{
display:block;
}
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>
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 am trying to print real-time user input from input tags by the user. I am even getting multiple user inputs from the child element to the parent element as a form of an object using useState. But whenever the user tries to fill the second input field, then the first input is re-render and it's replaced by the primary state which is an empty string.
code:-
Child Element
import React, { useState } from "react";
const Child = (props) => {
const [name, setName] = useState("");
const [age, setAge] = useState("");
let userData = {
name: "",
age: ""
};
const nameChangeHandler = (e) => {
setName(e.target.value);
userData.name = e.target.value;
};
const ageChangeHandler = (e) => {
setAge(e.target.value);
userData.age = e.target.value;
};
const formOnChageHandler = (e) => {
e.preventDefault();
props.getData(userData);
};
const fromOnSubmitHandler = (e) => {
e.preventDefault();
};
return (
<React.Fragment>
<form onChange={formOnChageHandler} onSubmit={fromOnSubmitHandler}>
<label htmlFor="name">Name:</label>
<input
id="name"
placeholder="Enter Name"
value={name}
onChange={nameChangeHandler}
/>
<br />
<label htmlFor="age">Age:</label>
<input
id="age"
placeholder="Enter Age"
value={age}
onChange={ageChangeHandler}
/>
</form>
</React.Fragment>
);
};
export default Child;
Parent Element
import React, { useState } from "react";
import Child from "./components/Child";
function App() {
const [name, setName] = useState("");
const [age, setAge] = useState("");
let userData = (data) => {
setName(data.name);
setAge(data.age);
};
return (
<React.Fragment>
<Child getData={userData} />
<h1>Your name is:{name}</h1>
<h1>Your age is:{age}</h1>
</React.Fragment>
);
}
export default App;
code sandbox Link- https://codesandbox.io/s/from-traversing-child-to-parent-to-another-child-ynwyqd?file=/src/App.js:0-441
How I can get both data being reflected by using onChange from child to parent element?
I suggest you accumulate the user data in one state.
Like this.
const [user, setUser] = useState({
name: "",
age: null
});
And put the state on the parent and pass as props, also just have one handleChange function to update both the name and age by the input id
Child.js
import React, { useState } from "react";
const Child = ({ user, setUser }) => {
const handleChange = (e) => {
setUser((prev) => ({
...prev,
[e.target.id]: e.target.value
}));
};
const formOnChageHandler = (e) => {
e.preventDefault();
};
const fromOnSubmitHandler = (e) => {
e.preventDefault();
};
return (
<React.Fragment>
<form onChange={formOnChageHandler} onSubmit={fromOnSubmitHandler}>
<label htmlFor="name">Name:</label>
<input
id="name"
placeholder="Enter Name"
value={user.name}
onChange={handleChange}
/>
<br />
<label htmlFor="age">Age:</label>
<input
id="age"
placeholder="Enter Age"
value={user.age}
onChange={handleChange}
/>
</form>
</React.Fragment>
);
};
export default Child;
App.js
import React, { useState } from "react";
import Child from "./components/Child";
function App() {
const [user, setUser] = useState({
name: "",
age: null
});
return (
<React.Fragment>
<Child user={user} setUser={setUser} />
<h1>Your name is:{user.name}</h1>
<h1>Your age is:{user.age}</h1>
</React.Fragment>
);
}
export default App;
CODESANDBOX
Try using the child component as below,
import React, { useState } from "react";
const Child = (props) => {
const [name, setName] = useState("");
const [age, setAge] = useState("");
let userData = {
name: name, // the value "name" comes for the local state will be listen to the onChange event every time
age: age // same applies here as well
};
const nameChangeHandler = (e) => {
setName(e.target.value);
};
const ageChangeHandler = (e) => {
setAge(e.target.value);
};
const formOnChageHandler = (e) => {
e.preventDefault();
props.getData(userData);
};
const fromOnSubmitHandler = (e) => {
e.preventDefault();
};
return (
<React.Fragment>
<form onSubmit={fromOnSubmitHandler}>
<label htmlFor="name">Name:</label>
<input
id="name"
placeholder="Enter Name"
value={name}
onChange={nameChangeHandler}
/>
<br />
<label htmlFor="age">Age:</label>
<input
id="age"
placeholder="Enter Age"
value={age}
onChange={ageChangeHandler}
/>
</form>
</React.Fragment>
);
};
export default Child;
just use simple one state to manage data. just take a look below example component created from your child component.
we simply use single object state.
use name prop as key to store value in state.
import React, { useState } from "react";
const Child = (props) => {
const [formData, setFormData] = useState({});
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setFormData({
...formData,
[e.target.name]: e.target.value,
});
};
const formOnChageHandler = (e) => {
e.preventDefault();
props.getData(userData);
};
const fromOnSubmitHandler = (e) => {
e.preventDefault();
};
return (
<React.Fragment>
<form onChange={formOnChageHandler} onSubmit={fromOnSubmitHandler}>
<label htmlFor="name">Name:</label>
<input
id="name"
placeholder="Enter Name"
value={name}
onChange={handleChange}
name="name"
/>
<br />
<label htmlFor="age">Age:</label>
<input
id="age"
placeholder="Enter Age"
value={age}
onChange={handleChange}
name="age"
/>
</form>
</React.Fragment>
);
};
export default Child;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
it happens because you dont watch to the state, try this:
Child.js
import React, { useState } from "react";
const Child = (props) => {
const [name, setName] = useState("");
const [age, setAge] = useState("");
let userData = {
name,
age
};
const nameChangeHandler = (e) => {
setName(e.target.value);
userData.name = e.target.value;
};
const ageChangeHandler = (e) => {
setAge(e.target.value);
userData.age = e.target.value;
};
const formOnChageHandler = (e) => {
e.preventDefault();
props.getData(userData);
};
const fromOnSubmitHandler = (e) => {
e.preventDefault();
};
return (
<React.Fragment>
<form onChange={formOnChageHandler} onSubmit={fromOnSubmitHandler}>
<label htmlFor="name">Name:</label>
<input
id="name"
placeholder="Enter Name"
value={name}
onChange={nameChangeHandler}
/>
<br />
<label htmlFor="age">Age:</label>
<input
id="age"
placeholder="Enter Age"
value={age}
onChange={ageChangeHandler}
/>
</form>
</React.Fragment>
);
};
export default Child;
Try this, i check in codesandbox and it works:
In App.js:
import React, { useState } from "react";
import Child from "./components/Child";
function App() {
const [name, setName] = useState("");
const [age, setAge] = useState("");
return (
<React.Fragment>
<Child name={name} age={age} setName={setName} setAge={setAge} />
<h1>Your name is:{name}</h1>
<h1>Your age is:{age}</h1>
</React.Fragment>
);
}
export default App;
In Child.js:
import React, { useState } from "react";
const Child = ({ name, age, setName, setAge }) => {
const nameChangeHandler = (e) => {
setName(e.target.value);
};
const ageChangeHandler = (e) => {
setAge(e.target.value);
};
const fromOnSubmitHandler = (e) => {
e.preventDefault();
};
return (
<React.Fragment>
<form onSubmit={fromOnSubmitHandler}>
<label htmlFor="name">Name:</label>
<input
id="name"
placeholder="Enter Name"
value={name}
onChange={nameChangeHandler}
/>
<br />
<label htmlFor="age">Age:</label>
<input
id="age"
placeholder="Enter Age"
value={age}
onChange={ageChangeHandler}
/>
</form>
</React.Fragment>
);
};
export default Child;
If you want to improve your code, you can research and use state management like: redux, zustand, react context,...
Hope it useful for you.
Hello everyone and thank you for reading this! Here is my problem that i can't solve:
My application has the following functionality:
There are 2 inputs, then a button, when clicked, 2 more inputs appear and a button to send data from all inputs to the console, however, in the additional field, one input is required. This is where my problem arises: now, if I called additional inputs and filled in all the data, they are transferred to the console, if I didn’t fill in the required field, an error message goes to the console, BUT. I also need, in the event that I did NOT call additional inputs, the data of 2 basic inputs was transferred to the console. At the moment I can't figure it out.
import React, { useState } from "react";
import ReactDOM from "react-dom/client";
import produce from "immer";
const FunctionalBlock = ({
id,
idx,
isDeleted,
toggleBlockState,
additionalValue,
additionalTitle,
setNewBlock,
index,
}) => {
return (
<div
style={{
display: "flex",
maxWidth: "300px",
justifyContent: "space-between",
}}
>
{!isDeleted ? (
<React.Fragment>
<strong>{idx}</strong>
<input
type="text"
value={additionalTitle}
onChange={(e) => {
const additionalTitle = e.target.value;
setNewBlock((currentForm) =>
produce(currentForm, (v) => {
v[index].additionalTitle = additionalTitle;
})
);
}}
/>
<input
type="text"
value={additionalValue}
onChange={(e) => {
const additionalValue = e.target.value;
setNewBlock((currentForm) =>
produce(currentForm, (v) => {
v[index].additionalValue = additionalValue;
})
);
}}
/>
<button onClick={toggleBlockState}>now delete me</button>
</React.Fragment>
) : (
<button onClick={toggleBlockState}>REVIVE BLOCK</button>
)}
</div>
);
};
const Application = () => {
const [newBlock, setNewBlock] = useState([]);
const [firstInput, setFirstInput] = useState("");
const [secondInput, setSecondInput] = useState("");
const getNewBlock = (idx) => ({
id: Date.now(),
idx,
isDeleted: false,
additionalValue: "",
additionalTitle: "",
});
const toggleIsDeletedById = (id, block) => {
if (id !== block.id) return block;
return {
...block,
isDeleted: !block.isDeleted,
};
};
const createOnClick = () => {
const block = getNewBlock(newBlock.length + 1);
setNewBlock([...newBlock, block]);
};
const toggleBlockStateById = (id) => {
setNewBlock(newBlock.map((block) => toggleIsDeletedById(id, block)));
};
const showInputData = () => {
newBlock.map((item) => {
if (item.additionalTitle.length < 3) {
console.log("it is less than 3");
} else if (!item.additionalTitle && !item.additionalValue) {
console.log(firstInput, secondInput);
} else {
console.log(
firstInput,
secondInput,
item.additionalTitle,
item.additionalValue
);
}
});
};
return (
<div>
<div>
<input
type="text"
value={firstInput}
onChange={(e) => {
setFirstInput(e.target.value);
}}
/>
<input
type="text"
value={secondInput}
onChange={(e) => {
setSecondInput(e.target.value);
}}
/>
</div>
<div>
<button onClick={createOnClick}>ADD NEW INPUTS</button>
</div>
<div>
{newBlock.map((block, index) => (
<FunctionalBlock
key={index}
{...block}
toggleBlockState={() => toggleBlockStateById(block.id)}
setNewBlock={setNewBlock}
index={index}
/>
))}
</div>
<button onClick={showInputData}>send data</button>
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Application />);
Here is this code on sandbox for those who decided to help me. Thank you!
https://codesandbox.io/s/vigilant-booth-xnef6t
I have a problem that my React app saving 2 same properties on one query.
After I enter the data in two input field and click Set button I receive double of same data.
CODE HERE
import React, { useState } from "react";
export default function App() {
const [queries, setQueries] = useState([]);
const [symbol, setSymbol] = useState("");
const [price, setPrice] = useState("");
const onChangeSymbol = e => {
setSymbol(e.target.value);
};
const onChangePrice = e => {
setPrice(e.target.value);
};
const onClick = () => {
if (symbol !== "" && price !== "") {
setQueries((queries) => {
queries.push(`${symbol}${price}`);
return queries;
});
setSymbol("");
setPrice("");
}
}
return (
<div className="App">
<h6>Price Alert History</h6>
<ul>
{queries.map(query => <li>{query}</li>)}
</ul>
<input
type="text"
placeholder="Symbol"
value={symbol}
onChange={onChangeSymbol}
/>
<input
type="number"
placeholder="Price"
value={price}
onChange={onChangePrice}
/>
<button type="submit" onClick={onClick}>Set</button>
</div>
);
}
GOAL: I just want to receive one property instead of double of it.
You need just to fix your function and it will work properly
const onClick = () => {
if (symbol !== "" && price !== "") {
setQueries((queries) => {
return [ ...queries, `${symbol}${price}`] // fix here
});
setSymbol("");
setPrice("");
}
}
import React, { useState } from "react";
export default function App() {
const [queries, setQueries] = useState([]);
const [symbol, setSymbol] = useState("");
const [price, setPrice] = useState("");
const onChangeSymbol = e => {
setSymbol(e.target.value);
};
const onChangePrice = e => {
setPrice(e.target.value);
};
const onClick = () => {
if (symbol !== "" && price !== "") {
setQueries((queries) => {
return [ ...queries, `${symbol}${price}`]
});
setSymbol("");
setPrice("");
}
}
return (
<div className="App">
<h6>Price Alert History</h6>
<ul>
{queries.map(query => <li>{query}</li>)}
</ul>
<input
type="text"
placeholder="Symbol"
value={symbol}
onChange={onChangeSymbol}
/>
<input
type="number"
placeholder="Price"
value={price}
onChange={onChangePrice}
/>
<button type="submit" onClick={onClick}>Set</button>
</div>
);
}
I would have refactored it so that the price and symbol would be an object with keys
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [queries, setQueries] = useState([]);
const [symbol, setSymbol] = useState("");
const [price, setPrice] = useState("");
const onClick = () => {
if (symbol !== "" && price !== "") {
const product = {
symbol: symbol,
price: price
};
setQueries([...queries, product]);
setSymbol("");
setPrice("");
}
};
return (
<div className="App">
<h6>Price Alert History</h6>
<ul>
{queries.map(query => (
<li>
{query.symbol} {query.price}
</li>
))}
</ul>
<input
type="text"
placeholder="Symbol"
value={symbol}
onChange={e => setSymbol(e.target.value)}
/>
<input
type="number"
placeholder="Price"
value={price}
onChange={e => setPrice(e.target.value)}
/>
<button type="submit" onClick={onClick}>
Set
</button>
</div>
);
}