0

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')
);

2
  • Just added it to the question! Commented Jun 5, 2020 at 18:51
  • is this what you want? When you submit the form, all the values of the inputs will be shown as a space separated string below the submit button Commented Jun 5, 2020 at 19:16

2 Answers 2

2

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!

Javascript

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"))

HTML

<div id="app"></div>

CSS

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;
}
Sign up to request clarification or add additional context in comments.

2 Comments

omg thank you so much. I am still figuring out how to use state and this clarified A LOT.
Glad it helped!
1

There are generally two ways to do this:

  1. React way
  2. Old school DOM way

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.

  1. So basically you should store all the values in your state, you probably should make it an array since your inputs'number is too many for hand writing and maybe uncertain
  2. Set onChange handler on every input or delegate this handler to ancestor for better design
  3. You have to come up a way to figure out which input you are updating, one simple solution is adding a custom html data-* 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 array

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.