Home > other >  Render an array of refs
Render an array of refs

Time:12-07

I have to perform the following steps on an array:

  • Create an array of refs outside the component
  • create a form
  • inside the form make a map of the array and render an input for each element
  • the input (when in focus) at the press of "enter" puts the next input in focus if there is any, otherwise it submits the form

My code is the following:

const array = new Array(5).fill(createRef());


const Step1 = () => {
   
    return (
        <>
            {/*Form  */}
           <form style={{margin:30}} >
                {/*- inside the form make a map of the array and render an input for each element, - the input (when in focus) at the press of "enter" puts the next input in focus if there is any, otherwise it submits the form */}
                {array.map((item, index) => {
                    return (
                        <input
                            key={index}
                            ref={item}
                            type="text"
                            placeholder={`Input ${index   1}`}
                            onKeyPress={(e) => {
                                if (e.key === "Enter") {
                                    if (array[index   1]) {
                                        array[index   1].current.focus();
                                    } else {
                                        e.preventDefault();
                                        console.log("submit");
                                    }
                                }
                            }}
                        />
                    );
                })}
                <button type="submit">Submit</button> 
           </form>
        </>
    )
}

export default Step1;

The last point doesn't work, how can I change the code to make it work?

CodePudding user response:

You have two problems. The main problem is your use of Array#fill() which when used like this fills the array with references to a single object. As such you are ending up with a single ref which you succesively assigning each input to. The solution is to map the array and return a new ref on each iteration.

const array = new Array(5).fill(null).map(() => createRef());
// or
const array = Array.from({length: 5}, () => createRef());

Your second problem is that enter automatically submits the form so you need to preventDefault() at the top level.

const { createRef } = React;

const array = Array.from({length: 5}, () => createRef());

const Step1 = () => {

  function focusNextRef(e, index) {
    e.preventDefault();
    if (e.key === 'Enter') {
      if (array[index   1]) {
        array[index   1].current.focus();
      } else {
        e.preventDefault();
        console.log('submit');
      }
    }
  }

  return (
    <div>
      <form style={{ margin: 30 }} >
        {array.map((item, index) => {
          return (
            <input
              key={index}
              ref={item}
              type="text"
              placeholder={'Input '   (index   1)}
              onKeyPress={(e) => focusNextRef(e, index)}
            />
          );
        })}
        <button type="submit">Submit</button>
      </form>
    </div>
  );
};

ReactDOM.render(
  <Step1 />,
  document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>

<div id="root"></div>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

@pilchard Thanks, now it functions.

  • Related