How to clear input values of dynamic form in react

Here's a codesandbox to show you how to reset the items: https://codesandbox.io/s/romantic-heisenberg-93qi7

I also left a note for you on how to get this to work with your API data, see the comment inside onChangeText()

The problem is that the inputs are not controlled by state as you have deduced. We should create an updated object for each item from your API, giving it a value prop.

index.js

import React from "react";
import ReactDOM from "react-dom";
import Cart from "./Cart";

import "./styles.css";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      Items: [],
      itemvalues: [{}]
    };
    this.onChangeText = this.onChangeText.bind(this);
    this.getItems = this.getItems.bind(this);
    this.handleReset = this.handleReset.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.findFieldIndex = this.findFieldIndex.bind(this);
    this.trimText = this.trimText.bind(this);
  }

  getItems = () => {
    /*if the data is coming from an API, store it in an array then .map() over it.
     we can add a value prop to the object like:
      so you can do something like:

      const newItems = [...apiData].map((item) => {
        return {
          ...item,
          value: ""
        }
      })

      this.setState({
        Items: newItems
      })
     */

    this.setState({
      Items: [
        {
          name: "item1",
          description: "item1",
          group: "groupA",
          dtype: "str",
          value: ""
        },
        {
          name: "item2",
          description: "item2",
          group: "groupA",
          dtype: "str",
          value: ""
        },
        {
          name: "item3",
          description: "item3",
          group: "groupB",
          dtype: "str",
          value: ""
        },
        {
          name: "item4",
          description: "item4",
          group: "groupB",
          dtype: "str",
          value: ""
        }
      ]
    });
  };

  onChangeText = e => {
    const updatedItems = [...this.state.Items].map(item => {
      if (item.name === e.target.name) {
        return {
          ...item,
          value: e.target.value
        };
      } else {
        return item;
      }
    });

    const updatedItemValues = [...updatedItems].reduce((obj, curr) => {
      if (!obj[curr.group]) {
        obj[curr.group] = [];
      }
      obj[curr.group] = [...obj[curr.group], { [curr.name]: curr.value }];
      return obj;
    }, {});

    this.setState({
      ...this.state,
      Items: updatedItems,
      itemvalues: updatedItemValues
    });
  };

  findFieldIndex = (array, name) => {
    return array.findIndex(item => item[name] !== undefined);
  };
  trimText(str) {
    return str.trim();
  }

  handleReset = () => {
    const resetedItems = [...this.state.Items].map(item => {
      return {
        ...item,
        value: ""
      };
    });

    this.setState(
      {
        ...this.state,
        Items: resetedItems,
        itemvalues: []
      },
      () => console.log(this.state)
    );
  };

  handleSubmit = () => {
    console.log(this.state.itemvalues);
  };

  render() {
    return (
      <div>
        {
          <Cart
            Items={this.state.Items}
            getItems={this.getItems}
            handleSubmit={this.handleSubmit}
            handleReset={this.handleReset}
            onChangeText={this.onChangeText}
          />
        }
      </div>
    );
  }
}

Cart.js

import React, { useEffect } from "react";
import Form from "./Form";

const Cart = props => {
  useEffect(() => {
    props.getItems(props.Items);
  }, []);

  return (
    <div>
      <Form Items={props.Items} onChangeText={props.onChangeText} />

      <button onClick={props.handleSubmit}>Submit</button>
      <button onClick={props.handleReset}>Reset</button>
    </div>
  );
};

export default Cart;

The Cart component can remain mostly the same, we do not need to pass in props.items to useEffect() dependency.

Form.js

import React from "react";

const Form = props => {
  return (
    <div>
      {props.Items.map(item => {
        return (
          <input
            name={item.name}
            placeholder={item.description}
            data-type={item.dtype}
            data-group={item.group}
            onChange={e => props.onChangeText(e)}
            value={item.value}
          />
        );
      })}
    </div>
  );
};
export default Form;

Now in Form component, we provide each input a value prop that is connected to the item our upper-most parent component-state.

That's pretty much all you need to reset the values.


See if that works for you:

Working example on CodeSandbox

enter image description here

Since you were already using hooks in part of your code, I've converted your class into a functional component using hooks (my advice: learn hooks and forget about class components).

I've added a value property to your INITIAL_STATE so it will keep the input value for each inputItem.

Full CODE:

index.js

import React, { useState } from "react";
import ReactDOM from "react-dom";
import FormV2 from "./FormV2";

import "./styles.css";

function App() {
  const INITIAL_STATE = [
    {
      name: "item1",
      description: "item1",
      group: "groupA",
      dtype: "str",
      value: "" // ADDED VALUE PROPERTY TO KEEP THE INPUT VALUE
    },
    {
      name: "item2",
      description: "item2",
      group: "groupA",
      dtype: "str",
      value: ""
    },
    {
      name: "item3",
      description: "item3",
      group: "groupB",
      dtype: "str",
      value: ""
    },
    {
      name: "item4",
      description: "item4",
      group: "groupB",
      dtype: "str",
      value: ""
    }
  ];

  const [inputItems, setInputItems] = useState(INITIAL_STATE);

  function handleChange(event, index) {
    const newValue = event.target.value;
    setInputItems(prevState => {
      const aux = Array.from(prevState);
      aux[index].value = newValue;
      return aux;
    });
  }

  function handleReset() {
    console.log("Reseting Form to INITIAL_STATE ...");
    setInputItems(INITIAL_STATE);
  }

  function handleSubmit() {
    inputItems.forEach(item =>
      console.log(
        "I will submit input: " + item.name + ", which value is: " + item.value
      )
    );
  }

  return (
    <FormV2
      handleSubmit={handleSubmit}
      handleReset={handleReset}
      handleChange={handleChange}
      inputItems={inputItems}
    />
  );
}

ReactDOM.render(<App />, document.getElementById("root"));

FormV2.js

import React from "react";

function FormV2(props) {
  const formInputItems = props.inputItems.map((item, index) => (
    <div key={item.name}>
      {item.name + ": "}
      <input
        type="text"
        data-type={item.dtype}
        data-group={item.group}
        placeholder={item.description}
        value={item.value}
        onChange={event => props.handleChange(event, index)}
      />
    </div>
  ));

  return (
    <React.Fragment>
      <form>{formInputItems}</form>
      <button onClick={props.handleSubmit}>Submit</button>
      <button onClick={props.handleReset}>Reset</button>
      <div>State: {JSON.stringify(props.inputItems)}</div>
    </React.Fragment>
  );
}

export default FormV2;