I have the following input:
<input :value="inputAmount" #input="handleAmountInput($event)" placeholder="Enter amount..." type="text">
I don't want 2-way binding with inputAmount because I want to clean the input of non-numeric characters in the handleAmountInput() function whenever the user inputs something:
handleAmountInput(e) {
const cleanInput = e.target.value.replace(/\D/g, '');
this.inputAmount = cleanInput;
console.log(cleanInput);
},
The issue is, the input itself doesn't reflect this cleaned up string set to inputAmount. If I show inputAmount in a separate element or console.log it like in the snippet above, it shows up just fine, but binding the value to the input with :value doesn't seem to work and shows the full inputted string, including non-numeric characters. What am I doing wrong here and how do I get the input to show the cleaned up string?
I'm not yet sure why exactly your code doesn't work as I would expect it to, but the way to fix it is to use both v-model and #input handler at the same time...
const app = Vue.createApp({
data() {
return {
inputAmount: ''
}
},
methods: {
handleAmountInput(e) {
this.inputAmount = e.target.value.replace(/\D/g, '');
console.log(this.inputAmount);
},
},
})
app.mount('#app')
<script src="https://unpkg.com/vue#3.1.5/dist/vue.global.js"></script>
<div id='app'>
<input v-model="inputAmount" #input="handleAmountInput($event)" placeholder="Enter amount..." type="text">
<pre>{{ inputAmount }}</pre>
</div>
Update
Ok, I now understand the reason why your code does not work. What happens:
Value of inputAmount is for example '123' (reflected in <input>)
User types a
Your #input handler is called. It receives the value '123a', do it's job creating cleaned value '123' and assigns it into inputAmount
From Vue POV the value of inputAmount did not changed at all so no re-render is required and <input> still shows '123a' even tho inputAmount has a value of '123'
So another way of fixing your code is just to assign some value <input> can never produce into inputAmount 1st just to trigger the update (demo below)
const app = Vue.createApp({
data() {
return {
inputAmount: ''
}
},
methods: {
handleAmountInput(e) {
this.inputAmount = null
this.inputAmount = e.target.value.replace(/\D/g, '');
console.log(this.inputAmount);
},
},
})
app.mount('#app')
<script src="https://unpkg.com/vue#3.1.5/dist/vue.global.js"></script>
<div id='app'>
<input :value="inputAmount" #input="handleAmountInput($event)" placeholder="Enter amount..." type="text">
<pre>{{ inputAmount }}</pre>
</div>
Have you tried using #change event
<input :value="message" #change="getInput($event)" placeholder="edit me" />
Use computed getter setter instead, Link :
example :
computed: {
inputAmount: {
get(){
//perform your logic
return 'value'
},
set(newValue){
this.value= newValue;
}
}
}
use v-model="inputAmount"? please see: https://cn.vuejs.org/v2/guide/forms.html
then you can just edit like this.inputAmount= this.inputAmount.replace(/\D/g, '');
Related
Consider a simple clock display and an input which I bound one-way to keep control over old/new state:
<div>{{ time }}</div>
<input ref="text" type="text" :value="text" style="width:95%">
<button type="button" #click="saveOnDiff">Save</button>
createApp({
...,
methods: {
saveOnDiff() {
const current = this.$refs.text.value;
// Compare current with old text + update if it changed.
...
}
},
mounted() {
const instance = this;
setInterval(() => instance.time = new Date(), 1000);
}
}).mount('#app');
The clock is updated each second. Unfortunately, this update spoils the input. Try it here: https://jsfiddle.net/dL78tsh9
How can I reduce binding updates to the absolute necessary ones? Some extra switch on one-way bindings like :value.lazy="text" would be helpful...
Changing time on each and every second will cause the whole template to be re-run after every 1 second. Which results everything in that template getting updated.
When a user types into <input> element, You aren't storing that value anywhere. You've got a :value to poke the value in but you aren't updating it when the value changes. The result will be that when Vue re-renders everything it will jump back to its original value.
Possible solution : Kindly ensure that your data is kept in sync with what the user types in. This could be done using v-model and watcher to get new and old values and based on that you can achieve this requirmeent.
You can try something like this (This is not a perfect solution but it will give you an idea) :
const {
createApp
} = Vue
const characterWiseDiff = (left, right) => right
.split("")
.filter(function(character, index) {
return character != left.charAt(index);
})
.join("");
createApp({
data() {
return {
result: "",
text: "Try to change me here",
time: new Date(),
oldVal: null
}
},
watch: {
text(newVal, oldVal) {
this.oldVal = oldVal;
}
},
methods: {
saveOnDiff() {
if (!this.oldVal) this.oldVal = this.text
const current = this.$refs.text.value;
console.log(current, this.oldVal)
if (current === this.oldVal) {
this.result = "No changes have been made!";
} else {
this.result = `Saved! Your changes were: "${characterWiseDiff(current, this.oldVal)}"`;
}
}
},
mounted() {
const instance = this;
setInterval(() => instance.time = new Date(), 1000);
}
}).mount('#app');
<script src="https://unpkg.com/vue#3.2.41/dist/vue.global.js"></script>
<div id="app">
<div>{{ time }}</div>
<input ref="text" type="text" v-model="text" style="width:95%">
<button type="button" #click="saveOnDiff">Save</button>
{{ result }}
</div>
As far as I know, there's no way to trick VueJs to not re-render a specific field.
When the time changes, your existing virtual DOM has a value for "text" and the newly generated virtual DOM has a different value so... VueJS re renders it.
UPDATE:
Based on #Tolbxela comment, looks like you could use v-once to only render the field once, and ignore the future DOM updates.
https://vuejs.org/api/built-in-directives.html#v-once
Alternative
If you want to control old/new state, why don't you just use two-way binding and save both states?
Something like this:
const {
createApp
} = Vue
const characterWiseDiff = (left, right) => right
.split("")
.filter(function(character, index) {
return character != left.charAt(index);
})
.join("");
createApp({
data() {
return {
result: "",
text: "Try to change me here",
previousText: "Try to change me here",
time: new Date(),
}
},
methods: {
saveOnDiff() {
if (this.text === this.previousText) {
this.result = "No changes have been made!";
} else {
this.result = `Saved! Your changes were: "${characterWiseDiff(this.previousText, this.text)}"`;
this.previousText = this.text;
}
}
},
mounted() {
const instance = this;
setInterval(() => instance.time = new Date(), 1000);
}
}).mount('#app');
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div>{{ time }}</div>
<div>
<input id="mockId" ref="text" type="text" v-model="text" style="width:95%">
<button type="button" #click="saveOnDiff">Save</button>
</div>
{{ result }}
</div>
https://jsfiddle.net/dmxLuf9w/6/
The best solution is to not use the Vue reactivity for timer updates at all. See my UPDATE 2 below.
The simplest way to fix it is to replace :value with v-model
UPDATE 1:
We need an other data field to store the input value.
<input ref="text" type="text" v-model="input" style="width:95%">
Check the sample below.
But it is not a good solution for complex apps, since every second you whole app HTML is refreshed. This can cause problems with rendering and lags.
UPDATE 1:
I have missed the other logic of comparing values. Here is the well working solution
UPDATE 2:
This question helped me to understand the whole problem with template rendering in Vue.
TransitionGroup lag when using requestAnimationFrame
And here is a good article about Improve Vue Performance with v-once + v-memo
CODE:
const placeholder = "Try to change me here"
const {
createApp
} = Vue
const characterWiseDiff = (left, right) => right
.split("")
.filter(function(character, index) {
return character != left.charAt(index);
})
.join("");
createApp({
data() {
return {
result: "",
text: placeholder,
input: placeholder,
time: new Date(),
}
},
methods: {
saveOnDiff() {
const current = this.input
if (current === this.text) {
this.result = "No changes have been made!";
} else {
this.result = `Saved! Your changes were: "${characterWiseDiff(this.text, current)}"`;
this.text = current;
}
}
},
mounted() {
const instance = this;
setInterval(() => instance.time = new Date(), 1000);
}
}).mount('#app');
<div id="app">
<div>{{ time }}</div>
<input ref="text" type="text" v-model="input" style="width:95%">
<button type="button" #click="saveOnDiff">Save</button>
{{ result }}
</div>
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>
The simplest way to fix it is to use v-memo="[text]":
<input ref="text" type="text" :value="text" style="width:95%" v-memo="[text]">
The <input> will only be updated when my text property has updated and not the any other property like the time property.
Test here:
https://jsfiddle.net/dL78tsh9/47/
I'm building a basic 'required' form validation function. Here's the function:
JS:
export default {
methods: {
required(string) {
if (!string) {
return 'This field is required!'
}
}
}
}
HTML:
<input id="username"
v-model="credentials.username"
type="text"
name="username"
/>
<span>{{ required(credentials.username) }}</span>
The above works great. If I start typing in the input, the returned value goes null. If I empty the input, the returned value comes back as expected, "This field is required".
My question is, how can I return the value as null/blank to start? Expected flow is:
Returned value is null/blank to start
User starts typing, nothing changes because string.length != 0
User deletes all characters, causing string.length == 0, causing the returned value to be 'This field is required!'
One solution is to use an input-event handler (called for every new value in the input) that sets a flag to indicate the field is "dirty". Then conditionally render the validation result (the <span>) based on the flag:
Declare a data property named "dirty":
export default {
data() {
return {
dirty: false,
}
}
}
In the template, add an input-event handler on the <input> that sets the dirty flag:
<input #input="dirty = true">
Also, conditionally render the <span> field based on dirty:
<span v-if="dirty">{{ required(credentials.username) }}</span>
demo
I am wanting to reset the name value in a swatch generator I am building, after the swatch is published, but struggling to get it right. Firstly, all the values in the app, 2 colors and swatch name, are watched and emitted. Here is the name value (value3) but the colors are set up the same, just value1 and value2 (not resetting the colors)
<b-form-input
id="name"
size="lg"
type="text"
class="search-bar"
placeholder="Name Your Swatch and Enter to Save"
v-model="value3"
ref="value3"
:value="value3"
#keypress="publishSwatch"
>
</b-form-input>
and what collects the name is here:
props: ['value'],
publishSwatch(e) {
this.$emit('input', {
value3: +this.$refs.value3.value,
});
if (e.key == "Enter") {
this.createSwatch();
this.resetForm(); //Not done yet
this.handleSwatch();
}
}
the relevant working part of the createSwatch function is just:
let name = (`${this.value3}`); //this works fine to set and output the inputted value
resetForm() {
// Stuck for what to put here
}
After the swatch is published I want to reset the placeholder to the default in resetForm() function, which I can place at the relevant place in publishSwatch method, which should be as above, but can't get anywhere near to getting it right. The colors are in another function and not resetting those. I have tried this, but it seems to have no relevance to how the inputs are set up:
resetForm() {
let clear = document.getElementById('name');
clear.input.value.reset();
}
And doesn't work
Tips welcome.
Thanks
Don't use :value and v-model together, because v-model creates :value automatically so there would be a conflict.
There is no need for a ref because the correct way is to use the v-model binding (value3) in the instance instead of a DOM value
HTML
<b-form-input
id="name"
size="lg"
type="text"
class="search-bar"
placeholder="Name Your Swatch and Enter to Save"
v-model="value3"
#keypress="publishSwatch">
</b-form-input>
Methods should look like this:
methods: {
publishSwatch(e) {
this.$emit('input', {
value3: +this.value3
});
if (e.key == "Enter") {
this.createSwatch();
this.resetForm();
this.handleSwatch();
}
},
resetForm() {
this.value3 = ''; // <-- Reset the instance value
}
}
Here is a demo
I have 2 inputs and want switch focus from first to second when user press Enter.
I tried mix jQuery with Vue becouse I can't find any function to focus on something in Vue documentation:
<input v-on:keyup.enter="$(':focus').next('input').focus()"
...>
<input ...>
But on enter I see error in console:
build.js:11079 [Vue warn]: Property or method "$" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option. (found in anonymous component - use the "name" option for better debugging messages.)warn # build.js:11079has # build.js:9011keyup # build.js:15333(anonymous function) # build.js:10111
build.js:15333 Uncaught TypeError: $ is not a function
You can try something like this:
<input v-on:keyup.enter="$event.target.nextElementSibling.focus()" type="text">
JSfiddle Example
Update
In case if the target element is inside form element and next form element is not a real sibling then you can do the following:
html
<form id="app">
<p>{{ message }}</p>
<input v-on:keyup.enter="goNext($event.target)" type="text">
<div>
<input type="text">
</div>
</form>
js
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
focusNext(elem) {
const currentIndex = Array.from(elem.form.elements).indexOf(elem);
elem.form.elements.item(
currentIndex < elem.form.elements.length - 1 ?
currentIndex + 1 :
0
).focus();
}
}
})
JSFiddle Example
Following up from #zurzui here is in my opinion a cleaner alternative using the $refs API (https://v2.vuejs.org/v2/api/#vm-refs).
Using the $refs API, can allow you to target element in a simpler fashion without traversing the DOM.
Example: https://jsfiddle.net/xjdujke7/1/
After some tests, it's working
new Vue({
el:'#app',
methods: {
nextPlease: function (event) {
document.getElementById('input2').focus();
}
}
});
<script src="https://vuejs.org/js/vue.js"></script>
<div id='app'>
<input type="text" v-on:keyup.enter="nextPlease">
<input id="input2" type="text">
</div>
directives: {
focusNextOnEnter: {
inserted: function (el,binding,vnode) {
let length = vnode.elm.length;
vnode.elm[0].focus();
let index = 0;
el.addEventListener("keyup",(ev) => {
if (ev.keyCode === 13 && index<length-1) {
index++;
vnode.elm[index].focus();
}
});
for (let i = 0;i<length-1;i++) {
vnode.elm[i].onfocus = (function(i) {
return function () {
index = i;
}
})(i);
}
}
}
}
// use it
<el-form v-focusNextOnEnter>
...
</el-form>
Try this:
<input ref="email" />
this.$refs.email.focus()
Whilst I liked the directives answer due to it working with inputs inside other elements (style wrappers and so on), I found it was a little inflexible for elements that come and go, especially if they come and go according to other fields. It also did something more.
Instead, I've put together the following two different directives. Use them in your HTML as per:
<form v-forcusNextOnEnter v-focusFirstOnLoad>
...
</form>
Define them on your Vue object (or in a mixin) with:
directives: {
focusFirstOnLoad: {
inserted(el, binding, vnode) {
vnode.elm[0].focus();
},
},
focusNextOnEnter: {
inserted(el, binding, vnode) {
el.addEventListener('keyup', (ev) => {
let index = [...vnode.elm.elements].indexOf(ev.target);
if (ev.keyCode === 13 && index < vnode.elm.length - 1) {
vnode.elm[index + 1].focus();
}
});
},
},
},
On an enter key pressed, it looks for the index of the current input in the list of inputs, verifies it can be upped, and focuses the next element.
Key differences: length and index are calculated at the time of the click, making it more suitable for field addition/removal; no extra events are needed to change a cached variable.
Downside, this will be a little slower/more intensive to run, but given it's based off UI interaction...
Vue.js's directive is good practice for this requirement.
Define a global directive:
Vue.directive('focusNextOnEnter', {
inserted: function (el, binding, vnode) {
el.addEventListener('keyup', (ev) => {
if (ev.keyCode === 13) {
if (binding.value) {
vnode.context.$refs[binding.value].focus()
return
}
if (!el.form) {
return
}
const inputElements = Array.from(el.form.querySelectorAll('input:not([disabled]):not([readonly])'))
const currentIndex = inputElements.indexOf(el)
inputElements[currentIndex < inputElements.length - 1 ? currentIndex + 1 : 0].focus()
}
})
}
})
Note: We should exclude the disabled and readonly inputs.
Usage:
<form>
<input type="text" v-focus-next-on-enter></input>
<!-- readonly or disabled inputs would be skipped -->
<input type="text" v-focus-next-on-enter readonly></input>
<input type="text" v-focus-next-on-enter disabled></input>
<!-- skip the next and focus on the specified input -->
<input type="text" v-focus-next-on-enter='`theLastInput`'></input>
<input type="text" v-focus-next-on-enter></input>
<input type="text" v-focus-next-on-enter ref="theLastInput"></input>
</form>
<input type="text" #keyup.enter="$event.target.nextElementSibling.focus() />
I'm trying to create a simple form with react, but facing difficulty having the data properly bind to the defaultValue of the form.
The behavior I'm looking for is this:
When I open my page, the Text input field should be filled in with the text of my AwayMessage in my database. That is "Sample Text"
Ideally I want to have a placeholder in the Text input field if the AwayMessage in my database has no text.
However, right now, I'm finding that the Text input field is blank every time I refresh the page. (Though what I type into the input does save properly and persist.) I think this is because the input text field's html loads when the AwayMessage is an empty object, but doesn't refresh when the awayMessage loads. Also, I'm unable to specify a default value for the field.
I removed some of the code for clarity (i.e. onToggleChange)
window.Pages ||= {}
Pages.AwayMessages = React.createClass
getInitialState: ->
App.API.fetchAwayMessage (data) =>
#setState awayMessage:data.away_message
{awayMessage: {}}
onTextChange: (event) ->
console.log "VALUE", event.target.value
onSubmit: (e) ->
window.a = #
e.preventDefault()
awayMessage = {}
awayMessage["master_toggle"]=#refs["master_toggle"].getDOMNode().checked
console.log "value of text", #refs["text"].getDOMNode().value
awayMessage["text"]=#refs["text"].getDOMNode().value
#awayMessage(awayMessage)
awayMessage: (awayMessage)->
console.log "I'm saving", awayMessage
App.API.saveAwayMessage awayMessage, (data) =>
if data.status == 'ok'
App.modal.closeModal()
notificationActions.notify("Away Message saved.")
#setState awayMessage:awayMessage
render: ->
console.log "AWAY_MESSAGE", this.state.awayMessage
awayMessageText = if this.state.awayMessage then this.state.awayMessage.text else "Placeholder Text"
`<div className="away-messages">
<div className="header">
<h4>Away Messages</h4>
</div>
<div className="content">
<div className="input-group">
<label for="master_toggle">On?</label>
<input ref="master_toggle" type="checkbox" onChange={this.onToggleChange} defaultChecked={this.state.awayMessage.master_toggle} />
</div>
<div className="input-group">
<label for="text">Text</label>
<input ref="text" onChange={this.onTextChange} defaultValue={awayMessageText} />
</div>
</div>
<div className="footer">
<button className="button2" onClick={this.close}>Close</button>
<button className="button1" onClick={this.onSubmit}>Save</button>
</div>
</div>
my console.log for AwayMessage shows the following:
AWAY_MESSAGE Object {}
AWAY_MESSAGE Object {id: 1, company_id: 1, text: "Sample Text", master_toggle: false}
Another way of fixing this is by changing the key of the input.
<input ref="text" key={this.state.awayMessage ? 'notLoadedYet' : 'loaded'} onChange={this.onTextChange} defaultValue={awayMessageText} />
Update:
Since this get upvotes, I will have to say that you should properly have a disabled or readonly prop while the content is loading, so you don't decrease the ux experience.
And yea, it is most likely a hack, but it gets the job done.. ;-)
defaultValue is only for the initial load
If you want to initialize the input then you should use defaultValue, but if you want to use state to change the value then you need to use value. Personally I like to just use defaultValue if I'm just initializing it and then just use refs to get the value when I submit. There's more info on refs and inputs on the react docs, https://facebook.github.io/react/docs/forms.html and https://facebook.github.io/react/docs/working-with-the-browser.html.
Here's how I would rewrite your input:
awayMessageText = if this.state.awayMessage then this.state.awayMessage.text else ''
<input ref="text" onChange={this.onTextChange} placeholder="Placeholder Text" value={#state.awayMessageText} />
Also you don't want to pass placeholder text like you did because that will actually set the value to 'placeholder text'. You do still need to pass a blank value into the input because undefined and nil turns value into defaultValue essentially. https://facebook.github.io/react/tips/controlled-input-null-value.html.
getInitialState can't make api calls
You need to make api calls after getInitialState is run. For your case I would do it in componentDidMount. Follow this example, https://facebook.github.io/react/tips/initial-ajax.html.
I'd also recommend reading up on the component lifecycle with react. https://facebook.github.io/react/docs/component-specs.html.
Rewrite with modifications and loading state
Personally I don't like to do the whole if else then logic in the render and prefer to use 'loading' in my state and render a font awesome spinner before the form loads, http://fortawesome.github.io/Font-Awesome/examples/. Here's a rewrite to show you what I mean. If I messed up the ticks for cjsx, it's because I normally just use coffeescript like this, .
window.Pages ||= {}
Pages.AwayMessages = React.createClass
getInitialState: ->
{ loading: true, awayMessage: {} }
componentDidMount: ->
App.API.fetchAwayMessage (data) =>
#setState awayMessage:data.away_message, loading: false
onToggleCheckbox: (event)->
#state.awayMessage.master_toggle = event.target.checked
#setState(awayMessage: #state.awayMessage)
onTextChange: (event) ->
#state.awayMessage.text = event.target.value
#setState(awayMessage: #state.awayMessage)
onSubmit: (e) ->
# Not sure what this is for. I'd be careful using globals like this
window.a = #
#submitAwayMessage(#state.awayMessage)
submitAwayMessage: (awayMessage)->
console.log "I'm saving", awayMessage
App.API.saveAwayMessage awayMessage, (data) =>
if data.status == 'ok'
App.modal.closeModal()
notificationActions.notify("Away Message saved.")
#setState awayMessage:awayMessage
render: ->
if this.state.loading
`<i className="fa fa-spinner fa-spin"></i>`
else
`<div className="away-messages">
<div className="header">
<h4>Away Messages</h4>
</div>
<div className="content">
<div className="input-group">
<label for="master_toggle">On?</label>
<input type="checkbox" onChange={this.onToggleCheckbox} checked={this.state.awayMessage.master_toggle} />
</div>
<div className="input-group">
<label for="text">Text</label>
<input ref="text" onChange={this.onTextChange} value={this.state.awayMessage.text} />
</div>
</div>
<div className="footer">
<button className="button2" onClick={this.close}>Close</button>
<button className="button1" onClick={this.onSubmit}>Save</button>
</div>
</div>
That should about cover it. Now that is one way to go about forms which uses state and value. You can also just use defaultValue instead of value and then use refs to get the values when you submit. If you go that route I would recommend you have an outer shell component (usually referred to as high order components) to fetch the data and then pass it to the form as props.
Overall I'd recommend reading the react docs all the way through and do some tutorials. There's lots of blogs out there and http://www.egghead.io had some good tutorials. I have some stuff on my site as well, http://www.openmindedinnovations.com.
it's extremely simple, make defaultValue and key the same:
<input defaultValue={myVal} key={myVal}/>
This is one of the recommended approaches at https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a-key
To force the defaultValue to re-render all you need to do is change the key value of the input itself. here is how you do it.
<input
type="text"
key={myDynamicKey}
defaultValue={myDynamicDefaultValue}
placeholder="It works"/>
Maybe not the best solution, but I'd make a component like below so I can reuse it everywhere in my code. I wish it was already in react by default.
<MagicInput type="text" binding={[this, 'awayMessage.text']} />
The component may look like:
window.MagicInput = React.createClass
onChange: (e) ->
state = #props.binding[0].state
changeByArray state, #path(), e.target.value
#props.binding[0].setState state
path: ->
#props.binding[1].split('.')
getValue: ->
value = #props.binding[0].state
path = #path()
i = 0
while i < path.length
value = value[path[i]]
i++
value
render: ->
type = if #props.type then #props.type else 'input'
parent_state = #props.binding[0]
`<input
type={type}
onChange={this.onChange}
value={this.getValue()}
/>`
Where change by array is a function accessing hash by a path expressed by an array
changeByArray = (hash, array, newValue, idx) ->
idx = if _.isUndefined(idx) then 0 else idx
if idx == array.length - 1
hash[array[idx]] = newValue
else
changeByArray hash[array[idx]], array, newValue, ++idx
Related issue
Setting defaulValue on control din't not update the state.
Doing reverse works perfectly:
Set state to default value, and the control UI gets updated correctly as if defaulValue was given.
Code:
let defaultRole = "Owner";
const [role, setRole] = useState(defaultRole);
useEffect(() => {
setMsg(role);
});
const handleChange = (event) => {
setRole(event.target.value );
};
// ----
<TextField
label="Enter Role"
onChange={handleChange}
autoFocus
value={role}
/>
Define a state for your default value
Surround your input with a div and a key prop
Set the key value to the same value as the defaultValue of the input.
Call your setDefaultValue defined at the step 1 somewhere to re-render your component
Example:
const [defaultValue, setDefaultValue] = useState(initialValue);
useEffect(() => {
setDefaultValue(initialValue);
}, false)
return (
<div key={defaultValue}>
<input defaultValue={defaultValue} />
</div>
)
Give value to parameter "placeHolder".
For example :-
<input
type="text"
placeHolder="Search product name."
style={{border:'1px solid #c5c5c5', padding:font*0.005,cursor:'text'}}
value={this.state.productSearchText}
onChange={this.handleChangeProductSearchText}
/>
Use value instead of defaultValue and change the value of the input with the onChange method.