简体   繁体   English

如何清除反应中动态形式的输入值

[英]How to clear input values of dynamic form in react

I have a dynamic form as a functional component which is generated via a class based component.我有一个动态表单作为功能组件,它是通过基于类的组件生成的。 I want to make reset button which clears the input field values and sets the state to null array.我想制作清除输入字段值并将状态设置为空数组的重置按钮。

Full code is available here: https://codesandbox.io/s/beautiful-archimedes-o1ygt完整代码可在此处获得: https : //codesandbox.io/s/beautiful-archimedes-o1ygt

I want to make a reset button, clearing all the input values and initializing the Itemvalues array to null.我想制作一个重置按钮,清除所有输入值并将 Itemvalues 数组初始化为 null。 Even if I set the values to null, it doesn't clear the input field.即使我将值设置为 null,它也不会清除输入字段。

However, the problem I'm facing is that since, it is a dynamic form and a functional component it doesn't have a predefined state for each individual form field making it difficult to set value to null.然而,我面临的问题是,由于它是一个动态表单和一个功能组件,它没有为每个单独的表单字段预定义状态,因此很难将值设置为 null。 Can someone please help, I'm stuck on this from a long time有人可以帮忙吗,我被困在这个很久了

Here's a codesandbox to show you how to reset the items: https://codesandbox.io/s/romantic-heisenberg-93qi7这是一个代码和框,向您展示如何重置项目: 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()我还为您留下了关于如何使其与您的 API 数据一起使用的注释,请参阅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.我们应该为 API 中的每个项目创建一个更新的对象,给它一个value属性。

index.js索引.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购物车.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. Cart 组件可以保持基本相同,我们不需要将props.items传递给useEffect()依赖项。

Form.js表单.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.现在在Form组件中,我们为每个输入提供一个 value 属性,该属性连接到我们最上面的父组件状态的项目。

That's pretty much all you need to reset the values.这几乎就是您重置值所需的全部内容。

See if that works for you:看看这是否适合你:

Working example on CodeSandbox CodeSandbox 上的工作示例

在此处输入图片说明

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 .我已经向您的INITIAL_STATE添加了一个value属性,因此它将保留每个inputItem的输入值。

Full CODE:完整代码:

index.js索引.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 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;

In order to control the values of the child components (Items) which I presume are input fields you need to be passing down their values from their parent component.为了控制我认为是输入字段的子组件(项目)的值,您需要从其父组件传递它们的值。 So each of your items will have an item.value which is stored in the parent component's state.因此,您的每个项目都有一个item.value ,它存储在父组件的状态中。

That means that in the parent component you will be able to define a method which clears all of the item values it is storing in its state.这意味着在父组件中,您将能够定义一个方法来清除它在其状态中存储的所有项目值。 That will probably look something like那可能看起来像

resetInputs = () => {
    this.setState({
        inputFields: this.state.inputFields.map(inputField => {
            ...inputField,
            value: ''
        }
    })
}

Also you'll need to write what kind of tag you want for your code to work, like input.此外,您还需要编写您希望代码工作的标签类型,例如输入。

So what you'll end up with for the code of the child component you shared is something like:因此,您共享的子组件的代码最终将类似于:

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

You want to manage the state of unknown number N of items, one way to achieve it is by managing a single object which contains all states, for example, setValuesManager manages N inputs and clicking the button reset its state:你想管理未知数量N项的状态,实现它的一种方法是通过管理包含所有状态的单个对象,例如, setValuesManager管理N输入并单击button重置其状态:

function TextAreaManager() {
  const [valuesManager, setValuesManager] = useState([...items]);
  return (
    <Flexbox>
      {valuesManager.map((value, i) => (
        <TextBoxItem
          key={i}
          value={value}
          onChange={e => {
            valuesManager[i] = e.target.value;
            setValuesManager([...valuesManager]);
          }}
        />
      ))}
      <PinkButton
        onClick={() =>
          setValuesManager([...Array(valuesManager.length).fill('')])
        }
      >
        Reset All
      </PinkButton>
    </Flexbox>
  );
}

Demo:演示:

编辑 OS Q 556724228 - 管理动态表单状态

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM