Javascript reactjs输入元素在击键后失去焦点

Javascript reactjs输入元素在击键后失去焦点,javascript,reactjs,Javascript,Reactjs,因此,我使用散列来存储动态创建的输入值行的值,在只输入一个字符后,我将失去对正在修改的输入的关注。我认为解决这个问题的方法可能是使用refs来重新关注最后一次更改的输入,但我无法让它工作,因为我无法确定如何指定最后更改的元素。关于如何解决这一问题的建议非常感谢 下面的代码动态创建输入框,并基于unitPriceValueHash查找其值。每个变量都有一个id,id用作散列的键 我创建了一个代码笔来尝试重新创建这个问题,但是我面临的问题没有出现在代码笔中。在我的实际应用程序中,例如在输入框中按1,

因此,我使用散列来存储动态创建的输入值行的值,在只输入一个字符后,我将失去对正在修改的输入的关注。我认为解决这个问题的方法可能是使用refs来重新关注最后一次更改的输入,但我无法让它工作,因为我无法确定如何指定最后更改的元素。关于如何解决这一问题的建议非常感谢

下面的代码动态创建输入框,并基于unitPriceValueHash查找其值。每个变量都有一个id,id用作散列的键

我创建了一个代码笔来尝试重新创建这个问题,但是我面临的问题没有出现在代码笔中。在我的实际应用程序中,例如在输入框中按1,则光标不再位于输入框上

codepen和my代码之间的唯一区别似乎是输入嵌套在一个表中


您共享的代码有几个问题

  • 不要使用内联函数。每次渲染时,都会再次创建该函数,这意味着当react比较道具时,该函数看起来不同(每次都是一个新的/不同的函数!),react将重新渲染
  • 不要修改状态中存在的任何对象,而是创建一个新对象。如果修改状态中存在的对象,本质上就是说不希望渲染保持一致性和可复制性
我已经重新发布了您的原始代码,并突出显示了问题

CreateItem(variant) {
  const unitPriceValueHash = this.props.unitPriceValueHash
  return {
    variant_title: variant.variant_title,
    variant_price: variant.variant_price,
    unit_cost: <TextField
      type="number"
      onChange={(event) => this.handleUnitPriceChange(variant.id, event)}
      // ^^^^ - inline functions cause react to re-render every time, instead - create a component
      key={variant.id}
      value={unitPriceValueHash[variant.id] || ''}
    />
  };
}

handleUnitPriceChange(id, event) {
  const unitPriceValueHash = this.state.unitPriceValueHash
  unitPriceValueHash[id] = event
  // ^^^^ - please, please - don't do this. You can't mutate the state like this.

  // instead, do the following to create a new modified object without modifying the object in the state
  const unitPriceValueHash = Object.assign({}, this.state.unitPriceValueHash, { id: event });
  this.setState({ unitPriceValueHash: unitPriceValueHash });
}
CreateItem(变量){
const unitPriceValueHash=this.props.unitPriceValueHash
返回{
变体标题:变体。变体标题,
变量价格:变量。变量价格,
单位成本:this.handleUnitPriceChange(variant.id,event)}
//^^^^-内联函数会导致react每次重新渲染,而不是-创建组件
key={variant.id}
value={unitPriceValueHash[variant.id]| |'''}
/>
};
}
handleUnitPriceChange(id、事件){
const unitPriceValueHash=this.state.unitPriceValueHash
unitPriceValueHash[id]=事件
//^^^^-请,请-不要这样做。你不能像这样改变状态。
//相反,请执行以下操作以创建新的已修改对象,而不修改状态中的对象
const unitPriceValueHash=Object.assign({},this.state.unitPriceValueHash,{id:event});
this.setState({unitPriceValueHash:unitPriceValueHash});
}
对于内联函数,通常建议为此创建一个新组件,该组件将值作为属性。可能是这样的:

class UnitCost extends PureComponent {
  static propTypes = {
    variantId: PropTypes.number,
    variantValue: PropTypes.object,
    onUnitPriceChange: PropTypes.func,
  }
  handleUnitPriceChange(e) {
    this.props.onUnitPriceChange(this.props.variantId, e)
  }
  render() {
    return (
      <TextField
        type="number"
        onChange={this.handleUnitPriceChange}
        value={this.props.variantValue || ''}
      />
    );
  }
}

CreateItem(variant) {
  const unitPriceValueHash = this.props.unitPriceValueHash
  return {
    variant_title: variant.variant_title,
    variant_price: variant.variant_price,
    unit_cost: (
      <UnitCost
        key={variant.id}
        variantId={variant.id}
        variantValue={unitPriceValueHash[variant.id]}
        onUnitPriceChange={this.handleUnitPriceChange}
      />
    ),
  };
}
类单位成本扩展了PureComponent{
静态类型={
variantId:PropTypes.number,
variantValue:PropTypes.object,
onUnitPriceChange:PropTypes.func,
}
handleUnitPriceChange(e){
this.props.onUnitPriceChange(this.props.variantId,e)
}
render(){
返回(
);
}
}
CreateItem(变量){
const unitPriceValueHash=this.props.unitPriceValueHash
返回{
变体标题:变体。变体标题,
变量价格:变量。变量价格,
单位成本:(
),
};
}
考虑到您对焦点的关注,react通常不会在重新渲染时丢失对象焦点,因此不要因为这个原因在更新后重新聚焦对象

react唯一会失去焦点的时间是它完全丢弃当前DOM树并从头开始。如果它认为父对象已被替换而不是修改,则会执行此操作。这可能是因为缺少
道具,或者
道具已更改


您没有发布足够的代码,我们无法对此进行进一步调查。如果您需要更多帮助,您应该构建一个我们可以运行和测试的最小可重复性示例。

这个问题的解决方案让我在更改时使用中间状态来存储输入字段的值,在更改时使用提交AJAX请求

class TextFieldWrapper extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: this.props.variantValue[this.props.variantId] || '',
    }
    this.handleUnitPriceChange = this.handleUnitPriceChange.bind(this)
    this.updateValue = this.updateValue.bind(this)
  }
  updateValue(value){
    this.setState({
      value: value,
    });
  }
  handleUnitPriceChange() {
    this.props.onUnitPriceChange(this.props.variantId, this.state.value);
  }
  render(){
    return (
      <TextField
        type="number"
        id={this.props.variantId}
        key={this.props.variantId}
        onChange={this.updateValue}
        onBlur={this.handleUnitPriceChange}
        value={this.state.value}
      />
    );
  }
}
类TextFieldWrapper扩展了React.Component{
建造师(道具){
超级(道具);
此.state={
值:this.props.variantValue[this.props.variantId]| |“”,
}
this.handleUnitPriceChange=this.handleUnitPriceChange.bind(this)
this.updateValue=this.updateValue.bind(this)
}
updateValue(值){
这是我的国家({
价值:价值,
});
}
handleUnitPriceChange(){
this.props.onUnitPriceChange(this.props.variantId,this.state.value);
}
render(){
返回(
);
}
}

caesay,感谢您富有洞察力的评论!我正在构建一个代码笔来复制这个问题。与此同时,我已经发布了完整的代码视图。创建代码笔需要一段时间,因为很多东西(比如变体)都来自rails后端。不要在道具中使用
.bind(this)
内联-它遇到了与我在回答中提到的相同的问题(每次渲染都会创建一个新函数)。最好在构造函数中执行此操作。
class UnitCost extends PureComponent {
  static propTypes = {
    variantId: PropTypes.number,
    variantValue: PropTypes.object,
    onUnitPriceChange: PropTypes.func,
  }
  handleUnitPriceChange(e) {
    this.props.onUnitPriceChange(this.props.variantId, e)
  }
  render() {
    return (
      <TextField
        type="number"
        onChange={this.handleUnitPriceChange}
        value={this.props.variantValue || ''}
      />
    );
  }
}

CreateItem(variant) {
  const unitPriceValueHash = this.props.unitPriceValueHash
  return {
    variant_title: variant.variant_title,
    variant_price: variant.variant_price,
    unit_cost: (
      <UnitCost
        key={variant.id}
        variantId={variant.id}
        variantValue={unitPriceValueHash[variant.id]}
        onUnitPriceChange={this.handleUnitPriceChange}
      />
    ),
  };
}
class TextFieldWrapper extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: this.props.variantValue[this.props.variantId] || '',
    }
    this.handleUnitPriceChange = this.handleUnitPriceChange.bind(this)
    this.updateValue = this.updateValue.bind(this)
  }
  updateValue(value){
    this.setState({
      value: value,
    });
  }
  handleUnitPriceChange() {
    this.props.onUnitPriceChange(this.props.variantId, this.state.value);
  }
  render(){
    return (
      <TextField
        type="number"
        id={this.props.variantId}
        key={this.props.variantId}
        onChange={this.updateValue}
        onBlur={this.handleUnitPriceChange}
        value={this.state.value}
      />
    );
  }
}