Here's a minimal working example of a component with a form of inputs created from a list, and one created from a single value:
import React from 'react';
export default class App extends React.Component {
constructor(props) {
super(props);
}
state = {
value: 'single value',
values: ['one', 'two'],
}
render() {
let test = this.state.values.map( (v, i) => {
return <input
key={ v }
value={ v }
onChange={ (e) => {
let values = this.state.values;
values[i] = e.target.value;
this.setState({ values });
} }
/>;
} )
return <div>
<form>
{ test }
</form>
<form>
<input
value={ this.state.value }
onChange={ (e) => this.setState({ value: e.target.value }) }
/>
</form>
</div>;
}
}
Which produces this:

When the user edits the third input field ('single value'), everything is fine. The user types something, the state updates, everyone is happy.
When the user edits either of the first two input fields however, the cursor loses focus immediately after the state is updated. To edit this field, the user must click on the field after any letter has been put in.
How do I solve this? Is there a way to prevent the component from blurring the <input>, or is there a better way to solve this?
I don't know how to record my screen and make a GIF from it. If you did not understand what I mean I suggest you create a React app with npx create-react-app my-app and edit my-app/src/App.js to my code example.
The problem is that you are passing the value as a key, for each new value you get a new key which react "thinks" its a new element thus re-mount the element and you loose the focus
Read more about keys
let test = this.state.values.map( (v, i) => {
return <input
key={ v }
value={ v }
onChange={ (e) => {
let values = this.state.values;
values[i] = e.target.value;
this.setState({ values });
} }
/>;
} )
Not sure if you can change the state structure, but i would go for a different approach and create a form object and give the name and key attributes according to the object's key.
Example:
class App extends React.Component {
state = {
form: {
name: "",
userName: "",
age: ""
},
externalValue: ""
};
onFormInputChange = ({ target }) => {
const { form } = this.state;
this.setState({
form: {
...form,
[target.name]: target.value
}
});
};
onInputChange = ({ target }) => {
this.setState({ [target.name]: target.value });
};
render() {
const { form } = this.state;
let test = Object.entries(form).map(([key, value]) => {
return (
<input
key={key}
name={key}
placeholder={key}
value={value}
onChange={this.onFormInputChange}
/>
);
});
return (
<div>
<form>{test}</form>
<form>
<input
name="externalValue"
placeholder="externalValue"
value={this.state.value}
onChange={this.onInputChange}
/>
</form>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<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>
<div id="root"/>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With