title: ReactJS: Adding multiple input fields of different types on click
body: <p>I've created a React app for a school project that can add multiple types of input fields to a view by clicking a button (sort of like Wordpress Gutenberg).</p>
  
  <p>Currently, I can add one of each type of item onto the view. However, if I click the button again, it erases the current text that was added. I'd like the ability to click the button to add as many fields as I'd like on click.</p>
  
  <p>Also, the items are only added into the view in the order they were created meaning, even if I choose photo first and I click headline after, it (headline) will appear at the top of the list above the initial item.</p>
  
  <p>I've had a look at these solutions (which were pretty good) but they didn't provide what I need.</p>
  
  <p><a href="https://stackoverflow.com/questions/54007949/dynamically-adding-input-form-field-issue-reactjs">Dynamically adding Input form field issue reactjs</a></p>
  
  <p>and "update delete list elements using unique key": <a href="https://www.youtube.com/watch?v=tJYBMSuOX3s" rel="nofollow noreferrer">https://www.youtube.com/watch?v=tJYBMSuOX3s</a>
  which was closer to what I needed to do.</p>
  
  <p>Apologies in advance for the length of the code,(there are two other related components for text input and an editform). I'm sure there is a much more simple way to do this. I haven't been able to find an npm package or solution to this specific problem online and am open to a simpler solution.</p>
  
  <p>Edit.jsx</p>
  
  <pre><code>export default class Edit extends React.Component {
    state = {
      texts: {
        hl: '',
        shl: '',
        txt: '',
        photo: []
      },
      coms: {
        hl: false,
        shl: false,
        txt: false,
        photo: null
      },
      labels: {
        // Replace with icons
        hl: 'Headline',
        shl: 'Sub',
        txt: 'Text Area',
        photo: 'Photo'
      },
      selectedItem: '',
    }
  
  
  
  
    componentDidMount() {
      const saveData = localStorage.getItem('saveData') === 'true';
      const user = saveData ? localStorage.getItem('user') : '';
      this.setState({ user, saveData });
    }
  
    createPage = async () =&gt; {
      await this.props.postPage(this.state.texts)
    }
  
    // add options
    addOptions = (item) =&gt; {
      const { coms } = this.state
      coms[item] = !coms[item]
      this.setState({ coms: coms })
    }
  
    // ADD TEXT
    addTxt = () =&gt; {
      this.setState({ texts: [...this.state.texts, ""] })
    }
  
    enableAllButtons = () =&gt; {
      this.setState({ selectedItem: '' })
    }
  
    handleChange = (e, index) =&gt; {
      this.state.texts[index] = e.target.value
      //set the changed state.
      this.setState({ texts: this.state.texts })
    }
  
    setDisable = (selectedItem) =&gt; {
      this.setState({ selectedItem })
    }
  
    handleRemove = () =&gt; {
      // this.state.texts.splice(index, 1)
      this.setState({ texts: this.state.texts })
    }
  
    handleSubmit = (e) =&gt; {
      console.log(this.state, 'all text')
    }
  
    handleChange = (e, item) =&gt; {
      let { texts } = this.state
      texts[item] = e.target.value
      //set the changed state.
      this.setState({ texts })
      console.log(texts)
    }
  
    render() {
      const { coms, labels, selectedItem, texts } = this.state
      let buttons = Object.keys(coms)
      let showItems = Object.keys(coms).filter(key =&gt; coms[key] === true)
  
      return (
        &lt;div&gt;
          &lt;InnerHeader /&gt;
          {/* Make a route for edit here */}
          &lt;Route path='/edit/form' render={() =&gt; (
            &lt;EditForm
              texts={texts}
              coms={coms}
              labels={labels}
              addOptions={this.addOptions}
              setDisable={this.setDisable}
              selectedItem={selectedItem}
              showItems={showItems}
              handleChange={this.handleChange}
              enableAllButtons={this.enableAllButtons}
            /&gt;
          )} /&gt;
  
          {/* Make route for preview */}
          &lt;Route path='/edit/preview' render={(props) =&gt; (
            &lt;Preview
              {...props}
              createPage={this.createPage}
            /&gt;
          )}
          /&gt;
        &lt;/div&gt;
      )
    }
  }
  </code></pre>
  
  <p>AddText.jsx:</p>
  
  <pre><code>
  export default class AddText extends Component {
  
    state = {
    }
  
    // ADD TEXT
    addTxt(item) {
      const {
        addOptions } = this.props
      addOptions(item)
    }
  
  
    render() {
      const { coms, labels } = this.props
      const { selectedItem } = this.props
      let buttons = Object.keys(coms)
      console.log('here', selectedItem)
      return (
        &lt;div&gt;
  
          &lt;Card&gt;
            &lt;Card.Body&gt;
              {
  
                buttons.map((item, index) =&gt; &lt;button
                  value={(selectedItem === "") ? false : (selectedItem === item) ? false : true} key={index} onClick={() =&gt; this.addTxt(item)}&gt;
                  {labels[item]}
                &lt;/button&gt;
                )
              }
            &lt;/Card.Body&gt;
          &lt;/Card&gt;
        &lt;/div&gt;
      )
    }
  }
  </code></pre>
  
  <p>EditForm.jsx</p>
  
  <pre><code>
  export default function EditForm(props) {
    return (
      &lt;div&gt;
  
        &lt;div className='some-page-wrapper-sm'&gt;
          &lt;div className="dash-card-sm"&gt;
            &lt;button&gt;&lt;Link to={{
              pathname: '/edit/preview',
              item: props.texts
            }}&gt;preview&lt;/Link&gt;&lt;/button&gt;
            &lt;br /&gt;
            &lt;br /&gt;
            &lt;AddText
              coms={props.coms}
              labels={props.labels}
              addOptions={props.addOptions}
              setDisable={props.setDisable}
              selectedItem={props.selectedItem}
            /&gt;
            &lt;div&gt;
              {
                props.showItems.map((item, index) =&gt; {
                  return (
  
                    &lt;InputFieldComponent
                      // setDisable={props.setDisable}
                      onChangeText={(e) =&gt; props.handleChange(e, item)}
                      enableAllButtons={props.enableAllButtons}
                      key={index}
                      item={item}
                      labels={props.labels}
                      texts={props.texts}
                    /&gt;
                  )
                })
              }
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    )
  }
  </code></pre>
  
  <p>InputFieldComponent.jsx</p>
  
  <pre><code>
  export default class InputFieldComponent extends React.Component {
  
  
    setWrapperRef = (node) =&gt; {
      this.wrapperRef = node;
    }
  
  
  
    render() {
      const { labels, item, onChangeText, texts } = this.props
      return (
        &lt;div&gt;
          &lt;textarea
            className="txt-box"
            ref={this.setWrapperRef}
            onChange={onChangeText}
            placeholder={labels[item]}
            value={texts[item]} /&gt;
        &lt;/div&gt;
      )
    }
  }
  </code></pre>