在React中需要像event.target.focus()这样的东西

时间:2018-07-24 20:20:00

标签: javascript reactjs event-handling focus onchange

我正在创建一个动态列表组件,该组件基本上会在每次向列表中添加内容时呈现一个新的空文本字段。该组件如下(它使用自定义TextFieldGroup,但我认为代码是不必要的,因为没有任何异常情况发生。):

const DynamicInputList = ({ inputs, onChangeArray, label, name, errors }) => 
{
  const nonEmptyInputs = inputs.filter(input => {
    return input !== "";
  });
  const lastIndex = nonEmptyInputs.length;
  return (
    <div>
      {nonEmptyInputs.map((input, index) => {
        return (
          <Grid container spacing={16} key={index}>
            <Grid item xs={12}>
              <TextFieldGroup
                label={label}
                id={`${name}${index}`}
                name={name}
                value={input}
                onChange={e => onChangeArray(e, index)}
                errors={errors[name]}
              />
            </Grid>
          </Grid>
        );
      })}
      <Grid container spacing={16} key={lastIndex}>
        <Grid item xs={12}>
          <TextFieldGroup
            label={label}
            id={`${name}${lastIndex}`} 
            name={name}
            value={inputs[lastIndex]}
            onChange={e => onChangeArray(e, lastIndex)}
            errors={errors[name]}
          />
        </Grid>
      </Grid>
    </div>
  );
};

onChangeArray函数如下:

  onChangeArray = (e, index) => {
    const state = this.state[e.target.name];
    if (e.target.value === "") {
      state.splice(index, 1);
      this.setState({ [e.target.name]: state });
    } else {
      state.splice(index, 1, e.target.value);
      this.setState({ [e.target.name]: state });
    }
  };

一切正常,除了更改空白字段(开始输入)时,它会立即将焦点从任何字段中移开。我正在寻找一种在保持关注这一领域的同时仍在下面添加新方法的方法。

谢谢。

1 个答案:

答案 0 :(得分:1)

问题是您遇到以下事件序列(假设inputs的长度为5):

  1. React渲染1个字段(键= 5)
  2. 用户开始输入“ a”
  3. 您的状态更改已触发
  4. React渲染2个全新字段(键= 1&值='a',键= 5),并丢弃旧字段(键= 5)

至少有两种解决方案

不要删除/触发重新渲染原始字段

这是更清洁的解决方案。

首先,由于that does an in-place modification,因此您正在使用onChangeArray直接在slice中改变状态。也许这现在并没有引起问题,但是它是一个很大的React反模式,可能会导致无法预测的行为。

以下是快速解决方法:

  onChangeArray = (e, index) => {
    const state = [...this.state[e.target.name]];
    if (e.target.value === "") {
      state.splice(index, 1);
      this.setState({ [e.target.name]: state });
    } else {
      state.splice(index, 1, e.target.value);
      this.setState({ [e.target.name]: state });
    }
  };

And other options

我将把实现的返工交给您,但要旨是:

  1. 使用一致的key引用,这意味着对所有inputs进行迭代,而只是跳过空的引用,而不是先查找空的引用并将该任意键设置为总长度。当然,您仍应将 first 设为空。
  2. 您可以考虑呈现所有内容,并根据需要使用CSS display:none属性来完成所需的UX

利用input的{​​{1}}属性

我假设您的autofocus使用TextFieldGroup元素。您可以将autofocus attribute传递到要关注的字段。这回答了您的原始问题。

但是不建议这样做,因为您仍然不需要经历这些重新渲染周期,然后在其顶部放置一个补丁。