所以我一直在尝试创建多个动态创建的受控输入。但是,如果我按下add ingredient
按钮添加输入,则在我向其添加文本时,新创建的输入不会保持焦点。
奇怪的事情(或线索)是第一个输入在添加新的输入之后保留焦点,只是添加的输入无法正常工作。
为了清晰起见,我以伪代码格式提出了我的问题:
if(Not react way of creating multiple dynamically created controlled inputs) {
question = How to create multiple dynamically created controlled inputs in React way?
} else {
question = How to make the dynamically created input retain focus?
}
代码是(工作jsfiddle代码段):
class Modal extends React.Component {
constructor(props){
super(props)
this.state = {
ingredients: [{ value: 'aap'}]
}
}
addIngredient(e) {
const old = this.state.ingredients
const newState = [...old, {value: ''}]
this.setState(
{ingredients: newState}
)
}
handleInput(e, i) {
console.log(e.target.value)
var newState = this.state.ingredients
newState[i].value = e.target.value
/*var promise = new Promise( (resolve, reject) => {
return this.setState({ ingredients: newState}) })
promise.then( () => {return e.target.focus()} ) */
this.setState( { ingredients: newState } )
e.target.focus()
}
render() {
const inputs = this.state.ingredients
return (
<div className="modal">
<div className="modal-box">
<form>
<h1>Create your recipe</h1>
<div>
<label>Recipe name:</label>
<input type="text" />
</div>
<div>
<label>Ingredients:</label>
{inputs.map( (input, i) => (
<input value={input.value} onChange={(e) => this.handleInput(e, i)} key={`${i}-${i * Math.random()}`} />
))}
<button id="ingredient-button" type="button" onClick={(e) => this.addIngredient(e)}><span>+</span>add ingredient</button>
</div>
</form>
</div>
</div>
);
}
}
ReactDOM.render(<Modal/>, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='root'></div>
答案 0 :(得分:2)
由于您的密钥是使用随机数生成的,因此每次DOM重新呈现它时都不会将其识别为相同的输入,从而失去焦点。我已将密钥更改为以下密钥以使其正常工作。
key={`ingredients-${i}`}
class Modal extends React.Component {
constructor(props){
super(props)
this.state = {
ingredients: [{ value: 'aap'}]
}
}
addIngredient(e) {
const old = this.state.ingredients
const newState = [...old, {value: ''}]
this.setState(
{ingredients: newState}
)
}
handleInput(e, i) {
var newState = this.state.ingredients
newState[i].value = e.target.value
/*var promise = new Promise( (resolve, reject) => {
return this.setState({ ingredients: newState}) })
promise.then( () => {return e.target.focus()} ) */
this.setState( { ingredients: newState } )
}
render() {
const inputs = this.state.ingredients
return (
<div className="modal">
<div className="modal-box">
<form>
<h1>Create your recipe</h1>
<div>
<label>Recipe name:</label>
<input type="text" />
</div>
<div>
<label>Ingredients:</label>
{inputs.map( (input, i) => (
<input value={input.value} onChange={(e) => this.handleInput(e, i)} key={`ingredients-${i}`} />
))}
<button id="ingredient-button" type="button" onClick={(e) => this.addIngredient(e)}><span>+</span>add ingredient</button>
</div>
</form>
</div>
</div>
);
}
}
ReactDOM.render(<Modal/>, document.getElementById('root'))
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='root'></div>
&#13;
答案 1 :(得分:0)
感谢Nelson Yeung查找密钥错误。但是为了关注每个创建的输入,它有助于使它们成为自己的类组件。这样您就可以访问生命周期方法。它们仍然可以被控制,但是它们会将onChange
回调传递给它们作为道具。
我将ref
与componentDidMount()
一起使用,将新组件精确聚焦一次(就在第一次安装时)。
class Input extends React.Component {
constructor(props){
super(props);
this.ref = null;
}
componentDidMount(){
this.ref.focus();
}
render(){
const {value, handleOnChange} = this.props
return <input value={ value } onChange={ handleOnChange } ref={ el => this.ref = el} />
}
}
class Modal extends React.Component {
constructor(props){
super(props)
this.state = {
ingredients: [{ value: 'aap'}]
}
}
addIngredient(e) {
const old = this.state.ingredients
const newState = [...old, {value: ''}];
this.setState(
{ingredients: newState}
)
}
handleInput(i) {
// return callback with the right index
return (e) => {
var newState = this.state.ingredients
newState[i].value = e.target.value
this.setState( { ingredients: newState } )
}
}
render() {
const inputs = this.state.ingredients
return (
<div className="modal">
<div className="modal-box">
<form>
<h1>Create your recipe</h1>
<div>
<label>Recipe name:</label>
<input type="text" />
</div>
<div>
<label>Ingredients:</label>
{inputs.map( (input, i) => (
<Input
value={input.value}
handleOnChange={this.handleInput(i)}
key={i}
/>
))}
<button id="ingredient-button" type="button" onClick={(e) => this.addIngredient(e)}><span>+</span>add ingredient</button>
</div>
</form>
</div>
</div>
);
}
}
ReactDOM.render(<Modal/>, document.getElementById('root'))
此处的工作代码示例:https://jsfiddle.net/jonahe/2ga02g6h/
编辑:我现在意识到我可能太快读了你的问题。也许你不需要/想要/要求专注于新创建的输入字段。