Reputation: 133
I am generating a random number of inputs which will each collect a word. I want to then take all of those individual words and create an array of words (eventually to display that array). I am new to react and am using onChange for my inputs but all I get is a blob of all the words together. I don't know how to take the index of each of the inputs and put it into an array on submit. I don't know if I should use onSubmit or onChange. I guess I am not sure how to collect the information from each input on submit. do I use key={index}
along with the event.target.value
, do I just make an array of event.target.value
?
Here is the Code Sandbox:
https://codesandbox.io/s/jovial-euler-swfs7?file=/src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import { Image } from './Image.js'
import { Button } from './Button.js'
import { images } from './assets/images.js'
import { Countdown } from './Countdown.js'
import { DisplayCount } from './DisplayCount.js'
import { Inputs } from './Inputs.js'
class Game extends React.Component{
constructor(props){
super(props)
this.timer = null
this.state = {
currentImg: 0,
timer: null,
ranNum: null,
thought: null
}
this.handleClick = this.handleClick.bind(this)
}
countdownClock = async (newRanNum) => {
const startingNum = newRanNum * 20;
for(let i = startingNum; i >= 0; i--) {
await new Promise(resolve => {
this.timer = setTimeout(() => {
this.setState({
timer: i
})
resolve()
}, 1000)
});
}
}
handleChange(event) {
this.setState({
thought: event.target.value
})
}
handleSubmit(event) {
}
generateInputs = (newRanNum) => {
const inputs = []
for(let i = 1; i <= newRanNum; i++){
inputs.push(
<Inputs type='text' onChange={this.handleChange} className='textInputs' />
)
}
return inputs;
}
handleClick(){
clearTimeout(this.timer)
let newRanNum = Math.floor(Math.random() * 20);
this.countdownClock(newRanNum)
this.generateInputs(newRanNum)
let current = this.state.currentImg;
let next = ++current % images.length;
this.setState({
currentImg: next,
ranNum: newRanNum
})
}
render(){
let src = this.state.currentImg;
return(
<div>
<Countdown name={'Countdown: '} countdown={this.state.timer} />
<DisplayCount name='Word Count: ' count={this.state.ranNum} />
<Image src={images[src]} />
<Button onClick={this.handleClick} />
<form onSubmit={this.handleSubmit}>
<ul>
{this.generateInputs(this.state.ranNum)}
</ul>
<input type='submit' value='Submit' />
</form>
</div>
)
}
}
ReactDOM.render(
<Game />,
document.getElementById('root')
);
Upvotes: 0
Views: 1254
Reputation: 368
There are generally two ways to do this:
The second one should be familiar: just get all input DOM by document.querySelectorAll
or something like that, and loop through the node list and get value via xx.value
The react way is a bit of verbose but maybe what you should do, the key is to make every input a controlled element, it means the value of input is passed by you and updated by you.
onChange
handler on every input or delegate this handler to ancestor for better designdata-*
attribute on every input and set it to current index, you can do this while generating inputs array. Then when you update, you get the input index from the change event and update to correspond position in value arrayUpvotes: 1
Reputation: 819
Here's a sample script to give you an idea on how you can handle this. There are, of course, many approaches including using other libraries. This one doesn't involve using any other library.
See Demo here: https://jsfiddle.net/p0djaw3f/1/
Hope this helps!
class SampleApp extends React.Component {
constructor(props) {
super(props)
// Generate Random Number of Inputs. Min of 2
const inputCount = Math.floor(Math.random() * 5) + 2
const inputArray = []
for (let ctr = 0; ctr < inputCount; ctr++) {
inputArray.push('')
}
this.state = {
inputs: inputArray
};
}
// Capture changes from input[type=text] and update state
onTextInputChanged(e, index) {
const inputs = [...this.state.inputs]
inputs[index] = e.target.value
this.setState({
inputs: inputs
})
}
// Display Content in Text Area
displayContent() {
const content = this.state.inputs.join('\n')
const target = document.getElementById('content')
target.value = content
}
render() {
return (
<div>
<h2>Random Inputs</h2>
<ol>
{this.state.inputs.map((input, index) => (
<li key={index}>
<label>
<input type="text" value={input} onChange={e => this.onTextInputChanged(e, index)} />
</label>
</li>
))}
</ol>
<button onClick={this.displayContent.bind(this)}>Display Content</button>
<h2>Display Inputs</h2>
<textarea id="content"></textarea>
</div>
)
}
}
ReactDOM.render(<SampleApp />, document.querySelector("#app"))
<div id="app"></div>
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin: 15px 0 15px 0;
}
input {
margin-right: 5px;
}
textarea {
height: 100px;
}
Upvotes: 2