Reputation: 458
Novice in React here.
Check EDIT1 for latest update
I have a input field and when I write some data in it and then click the button to insert it the data remains in input field.
Here is screenshot after I click Set
button.
As you can see the data in both fields remains, but I wish it disappear after I click the button.
As well with that after I click second time Set
button I receive double of undefined
.
Goal: Store the data after clicking Button in a column type. That I can enter multiple time data.
CODE HERE
import React, { useState } from "react";
import { Button} from "react-bootstrap";
export default function App() {
const [name, setName] = useState(null);
let tmpName;
let tmpPrice;
const onChangeSymbol = e => {
tmpName = e.target.value;
}
const onChangePrice = e => {
tmpPrice = e.target.value;
}
return (
<div className="App">
<h6>Price Alert History</h6>
{name}
<input type="text" placeholder="Symbol" onChange={onChangeSymbol}/>
<input type="number" placeholder="Price" onChange={onChangePrice}/>
<button onClick={() => setName(tmpName + ' ' + tmpPrice)}>Set</button>
</div>
);
}
EDIT1
After adding @macborowy answer, I face the problem that every time when I enter query I receive it double, check screenshot.
Upvotes: 0
Views: 689
Reputation: 31
So what is happening in your case:
setName
your component is rerendered and variables are cleared. That's what you see when you click on button -> it sets state, the component is rerendered and your variables are declared with default values again.value
to your inputs.In React such elements as <input>
, <textarea>
, and <select>
can be either controlled or uncontrolled components.
Controlled means, that you provide value
for them and control what you display. In that case, you need to use some state, to store current value: in your case you use hook useState
, so React controls what is displayed in those components and on callbacks you can get changes and then update your stored variable.
import React, { useState, useCallback } from "react";
export default function App() {
// could be replace with useReducer
const [name, setName] = useState(null);
const [tmpName, setTempName] = useState("");
const [tmpPrice, setTempPrice] = useState("");
const onChangeSymbol = useCallback(e => setTempName(e.target.value), []);
const onChangePrice = useCallback(e => setTempPrice(e.target.value), []);
const handleSubmit = useCallback(() => {
setName(`${tmpName} ${tmpPrice}`);
setTempName("");
setTempPrice("");
}, [tmpName, tmpPrice]);
return (
<div className="App">
<h6>Price Alert History</h6>
{name}
<input type="text" value={tmpName} placeholder="Symbol" onChange={onChangeSymbol} />
<input type="number" value={tmpPrice} placeholder="Price" onChange={onChangePrice} />
<button onClick={handleSubmit}>Set</button>
</div>
);
}
Uncontrolled is a bit different thing: you do not need to provide values and control component and can instead pass ref, with which you can access values of DOM node
import React, { useState, useRef, useCallback } from "react";
export default function App() {
const [name, setName] = useState(null);
const nameInput = useRef();
const numberInput = useRef();
const handleSubmit = useCallback(() => {
setName(`${nameInput.current.value} ${numberInput.current.value}`);
nameInput.current.value = "";
numberInput.current.value = "";
}, []);
return (
<div className="App">
<h6>Price Alert History</h6>
{name}
<input type="text" placeholder="Symbol" ref={nameInput} />
<input type="number" placeholder="Price" ref={numberInput} />
<button onClick={handleSubmit}>Set</button>
</div>
);
}
More info on https://reactjs.org/docs/forms.html
Upvotes: 0
Reputation: 1534
Try this:
const { useState } = React;
function App() {
const [name, setName] = useState(null);
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 !== "") {
setName(symbol+ ' ' + price);
setSymbol("");
setPrice("");
}
}
return (
<div className="App">
<h6>Price Alert History</h6>
{name}
<input type="text" placeholder="Symbol" value={symbol} onChange={onChangeSymbol}/>
<input type="number" placeholder="Price" value={price} onChange={onChangePrice}/>
<button onClick={onClick}>Set</button>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Update:
the last thing to ask, is it possible to store more that 1 query? Cause when I write the second query in both input fields and press Set button, appears the new query and old one is deleted. How can I store multiple queries?
Sure, instead of storing last query in the state, you need to push it to an array of queries. Then render contents of this array using map()
.
Here, I use a second form of setQueries()
that accepts a function rather than an object. That function will receive the previous state as the first argument.
Here is an example:
const { useState } = React;
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 onClick={onClick}>Set</button>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Upvotes: 1
Reputation: 1340
Here is what you could do:
import React, { useState } from "react";
import { Button} from "react-bootstrap";
export default function App() {
const [name, setName] = useState(null);
const [price, setPrice] = useState();
let tmpName;
let tmpPrice;
const onChangeSymbol = e => {
setName(e.target.value);
}
const onChangePrice = e => {
setPrice(e.target.value);
}
const handleSubmit = () => {
console.log(name, price);
setName();
setPrice();
}
return (
<div className="App">
<h6>Price Alert History</h6>
{name}
<input value={name} type="text" placeholder="Symbol" onChange={onChangeSymbol}/>
<input value={price} type="number" placeholder="Price" onChange={onChangePrice}/>
<button onClick={() => handleSubmit()}>Set</button>
</div>
);
}
First of all, do not use "tmp" variables. That is what useState()
is for. If you go with what I've posted, on every change of the inputs (on every keypress) the value will be saved to name
and price
. Once you hit submit, you can use the data however you want (print it to the console, call an API with it...) and then reset the name
and price
. The values in the inputs will be erased as well because we added value={name}
and value={price}
to them so in a way they are "linked".
Upvotes: 0