admin管理员组

文章数量:1387322

I'm creating a dynamic list ponent that basically renders a new empty text field every time something is added to the list. The ponent is as follows (it uses a custom TextFieldGroup but I don't think that code is necessary as nothing out of the ordinary is going on.):

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>
  );
};

The onChangeArray function is as follows:

  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 });
    }
  };

Everything works fine except when a blank field is changed (begin to type) it immediately removes focus from any of the fields. I'm looking for a way to keep the focus on this field while still adding the new one below.

Thanks in advance.

I'm creating a dynamic list ponent that basically renders a new empty text field every time something is added to the list. The ponent is as follows (it uses a custom TextFieldGroup but I don't think that code is necessary as nothing out of the ordinary is going on.):

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>
  );
};

The onChangeArray function is as follows:

  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 });
    }
  };

Everything works fine except when a blank field is changed (begin to type) it immediately removes focus from any of the fields. I'm looking for a way to keep the focus on this field while still adding the new one below.

Thanks in advance.

Share Improve this question asked Jul 24, 2018 at 20:20 Adam JohnstonAdam Johnston 1,4112 gold badges13 silver badges24 bronze badges 1
  • please elaborate it.. Everything works fine except when a blank field is changed (begin to type) it immediately removes focus from any of the fields. – Shubham Agarwal Bhewanewala Commented Jul 24, 2018 at 20:54
Add a ment  | 

1 Answer 1

Reset to default 2

The problem is that you're encountering the following sequence of events (assuming inputs length of 5):

  1. React renders 1 field (key = 5)
  2. User starts typing 'a'
  3. Your state change is triggered
  4. React renders 2 entirely new fields (key = 1 & value = 'a', key = 5) and trashes the old one (key = 5)

There are at least two solutions

Don't delete / trigger re-render of the original field

This is the cleaner solution.

First, you are directly mutating state in onChangeArray with your use of slice, because that does an in-place modification. Perhaps this isn't causing problems now, but it's a big React anti-pattern and could create unpredictable behavior.

Here's a quick fix:

  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

I'll leave the reworking of the implementation to you, but the gist would be:

  1. Use consistent key references, which means iterate over all your inputs and just skip the empty ones instead of finding the empty ones first and setting that arbitrary key to the total length. Of course, you should still render the first empty one.
  2. You could consider rendering everything, and use CSS display:none attribute as needed to acplish your desired UX

Leverage input's autofocus attribute

I assume your TextFieldGroup uses an input element. You could pass the autofocus attribute to the field you want to have focus. This answers your original question.

But this isn't remended, as you're still needlessly running through those re-render cycles and then putting a patch on top.

本文标签: javascriptneed something like eventtargetfocus() in ReactStack Overflow