How do you properly add all the input fields into one ref array?

Viewed 44

I am creating an app where I get a sentence from my server, randomly rearrange the letters, and display the randomized sentence on the client with the appropriate amount of input fields = to the number of letters in the sentence. I am trying to add all the input fields using a ref to iterate over all input fields so when the user types a letter the will get moved to the next input field. I am still a little confused as to how I can achieve this.

my js file:

const App = () => {
    const [sentence, setSentence] = useState('')
    const [score, setScore] = useState(0)
    const [words, setwords] = useState([])
    const [letters, setLetters] = useState([])
    const [guess, setGuess] = useState()
    const inputs = useRef([]);


    useEffect(() =>{
        axios.get('http://localhost:3001/sentence/1').then( res =>{
            console.log(res.data.data.sentence)
            setSentence(res.data.data.sentence)
            setGuess(new Array(res.data.data.sentence.length - 1))
            setwords(res.data.data.sentence.split(' '))
        })
    }, [])

    useEffect(() =>{
        words.forEach((word, index) => {
            if(index !== words.length - 1){
                words[index] = word + ' '
                setLetters(prev => [...prev, word + ' '])
            }
            else{
                setLetters(prev => [...prev, word])
            }
        })
    },[words])

    const handleChange = (event, temp) =>{
        console.log(inputs)
    }

    const handleEvent = () => {

    }
    let temp = -1
    return(
        <div className="main-content">
            <div className='sentence-scramble'>
                <ScrambleSentence sentence={sentence}/>
            </div>
            <div className='text'>
                The yellow blocks are meant for spaces
            </div>
            <div className='score'>
                Score: {score}
            </div>
            {words ?   
                words.map((word, idx)=>{
                    return(
                        <div className='input-guesser' key={idx}>
                            {word.split('').map((letter, index)=>{
                                if(letter === ' '){
                                    temp += 1
                                    return(
                                        <input
                                            className='space-inputs'
                                            maxLength= '1'
                                            key={index}
                                            onChange={(event) => handleChange(event, temp)}
                                            onKeyDown={(event) => handleEvent(event, index)}
                                            ref={el => inputs.current[temp] = el}
                                        />
                                    )
                                }
                                else{
                                    temp +=1
                                    return(
                                        <input
                                            className='input-fields'
                                            maxLength= '1'
                                            key={index}
                                            onChange={(event) => handleChange(event, temp)}
                                            onKeyDown={(event) => handleEvent(event, index)}
                                            ref={el => inputs.current[temp] = el}
                                        />
                                    )
                                }
                            })}
                        </div>
                    )
                })
            :null}
        </div>
    )
}

export default App;

my SCSS file:

.main-content{
    height: 75vh;
    width: 60%;
    background-color: gray;
    position: absolute;
    top: 12.5%;
    left: 23.5%;
    display: flex;
    flex-direction: column;

    .sentence-scramble{
        margin-top:25px;
        text-align: center;
    }


    .text{
        margin-top: 25px;
        text-align: center;
    }

    .score{
        text-align: center;
    }

    .input-guesser{
        width: 100%;
        display: flex;
        margin-bottom: 10px;
        .input-fields{
            width: 100%;
            margin-left: 5px;
            margin-right: 5px;
            border-radius: 5px;
            text-align: center;
        }
        .space-inputs{
            width: 100%;
            margin-left: 5px;
            margin-right: 5px;
            border-radius: 5px;
            background-color: #ffb74d;
            text-align: center;
        }
    }
}

and for some reason, only the last input field is captured while all other input fields all null. Any help is appreciated!

1 Answers

Why not just use a querySelector and store all the inputs there? it seems not very react-ish way but it'll work just fine

  useEffect(() => {
    const parent = document.querySelector(".inputs-parent");
    const allInputs = parent.querySelectorAll("input");

    inputsRef.current = allInputs;
  }, [])
Related