I'm new and trying to do something but can't THINK of a way (that works) to do so. I have the following situation:
- Array with 5 cells that can hold one char, I am sending each cell as a prop to an Input tag, in my custom Input react component I want to update that cell to hold a key, but can't do so.
My code:
import React, { useState, useEffect } from 'react'
import Input from './Input'
const makeWords = require('make-words')
function Body() {
const [word, setWord] = useState(makeWords.getWordByLength(5)) //create new word
const [guess, setGuess] = useState('') //saves guess from user
let information = ['','','','',''] //array with 5 cells
useEffect(() => { //when information array gets updated, set the guess to the new array value (toString)
setGuess(information.join(''))
}, [information])
return (
<div>
<h1 className='secret-word'>{word}</h1>
<Input className='letter-guess' info={information[0]}/>
<Input className='letter-guess' info={information[1]}/>
<Input className='letter-guess' info={information[2]}/>
<Input className='letter-guess' info={information[3]}/>
<Input className='letter-guess' info={information[4]}/>
</div>
)
}
export default Body
and
import React, { useEffect, useState } from 'react'
function Input({ className, info }) {
let [character, setCharacter] = useState('')//hold the character
function onChangeEvent(event) { // handles key input to save character
event.target.value = event.target.value.slice(-1)
setCharacter(event.target.value)
}
return (
<input type="text" className={className} onChange={onChangeEvent}/>// input tag
)
}
export default Input
I would really appreciate any help especially one with explanation, thanks a lot!
CodePudding user response:
You are storing the state of the word
in both the Input
and Body
components. It is generally not good practice to store the same state in two separate places. Try something like this instead:
function Body() {
const [word, setWord] = useState(makeWords.getWordByLength(5))
const [guess, setGuess] = useState('')
const [information, setInformation] = useState(['','','','',''])
useEffect(() => {
setGuess(information.join(''))
}, [information])
return (
<div>
<h1 className='secret-word'>{word}</h1>
<Input className='letter-guess' handleChange={setInformation} info={information} index={1} />
<Input className='letter-guess' handleChange={setInformation} info={information} index={2} />
<Input className='letter-guess' handleChange={setInformation} info={information} index={3} />
<Input className='letter-guess' handleChange={setInformation} info={information} index={4} />
<Input className='letter-guess' handleChange={setInformation} info={information} index={5} />
</div>
)
}
Then the Input
component would look like this:
function Input({ className, handleChange, info, index }) {
function updateInformation(e) {
handleChange(() => {
const newInfo = info;
newInfo[index] = e.target.value;
return newInfo;
});
}
return (
<input type="text" className={className} onChange={
(e) => updateInformation(e)}/>
)
}
This code is probably too long but I think it gets the idea across. Pass the current state of information
and the setInformation
function as props to the Input
. Then when any input changes, use the index to update the value and pass it to the setInformation
function.
CodePudding user response:
I'm not quite sure I understood your problem, but I think you want to be able to modify the prop info that you receive from your parent.
In that case the simplest way to do that is to have a state with the value and the setter in the parent, and pass to the child both the value and the setter. The children now gets the value as a prop and also the function to modify that value when it wants.