Home > database >  How can I create an array of React.RefObjects
How can I create an array of React.RefObjects

Time:02-08

I have a custom pin input of 5 input fields. My goal is to have control of the next input via reference. so I can perform an action like reference.focus() or reference.unfocus().

Presently my code looks like this:

const PinInput = ({ ...props }: Props): JSX.Element => {
  const [value, setValue] = useState<Array<string>>(Array.from({ length: 6 }, () => ''));
  const inputRef = React.useRef<HTMLInputElement>(null);

  return (
    <Box sx={{ display: 'flex', justifyContent: 'space-between', flexDirection: 'row' }}>
      {_.times(6, (i) => (
        <TextField
          key={i.toString()}
          id={i.toString()}
          className="pinError"
          placeholder={props.placeholder}
          sx={{
            borderRadius: '4px',
          }}
          inputRef={inputRef}
          inputProps={{
            inputMode: 'numeric',
            size: 3,
            maxLength: 1,
            style: {
              color: colors.errorDefault,
              textAlign: 'center',
              backgroundColor: colors.error80,
              caretColor: colors.transparent,
            },
          }}
          required
          value={value[i]}
          onKeyDown={(event) => {
            if (event.key === 'Backspace') { console.log(event.key); }
          }}
          onChange={(event) => {
            value[i] = event.target.value;
            setValue([...value]);
            inputRef?.current?.focus();
            if (props.onChange) props.onChange(event);
          }}
        />
      ))}
    </Box>
  );
};

But the issue is now, I have only one inputRef for all the input pins. how can I make this dynamic. I tried this:

const refs = Array.from({ length: 6 }, () => React.useRef<HTMLInputElement>(null));

but was met with the error: React Hook "React.useRef" cannot be called inside a callback.

CodePudding user response:

You need to create an array of Refs to manage all your inuts separately. Here is a repro on Stackblitz (Based on MUI's provided stackblitz of TextField) and here is the code :

import * as React from 'react';
import Box from '@mui/material/Box';
import TextField from '@mui/material/TextField';
import * as _ from 'lodash';

export default function BasicTextFields() {
  const inputRefs = React.useRef([]);

  React.useEffect(() => {
    console.log(inputRefs.current);
  });

  return (
    <Box
      component="form"
      sx={{
        '& > :not(style)': { m: 1, width: '25ch' },
      }}
      noValidate
      autoComplete="off"
    >
      {_.times(6, (i) => (
        <TextField
          key={Math.random()}
          inputRef={(el) => (inputRefs.current[i] = el)}
          defaultValue={`input number ${i}`}
          id="outlined-basic"
          label="Outlined"
          variant="outlined"
        />
      ))}
    </Box>
  );
}

You can see in the console that an array of refs is displayed.

  •  Tags:  
  • Related