【问题标题】:How to clear input values of dynamic form in react如何在反应中清除动态形式的输入值
【发布时间】:2019-11-05 12:46:11
【问题描述】:

我有一个动态表单作为功能组件,它是通过基于类的组件生成的。我想制作清除输入字段值并将状态设置为空数组的重置按钮。

此处提供完整代码: https://codesandbox.io/s/beautiful-archimedes-o1ygt

我想制作一个重置按钮,清除所有输入值并将 Itemvalues 数组初始化为 null。 即使我将值设置为 null,它也不会清除输入字段。

但是,我面临的问题是,由于它是一个动态表单和一个功能组件,它没有为每个单独的表单字段预定义状态,因此很难将值设置为 null。 有人可以帮忙吗,我卡在这个问题上很久了

【问题讨论】:

  • 是否要保留字段但重置值? Items 数组中的对象是什么样子的?
  • 你的代码不可读并且有语法错误,修复它。
  • 项目是如何开始生成的?
  • 在示例代码中,我手动生成了它们,但在实际代码中,数组是从 API 填充的
  • @user8306074 明白了,正在为你做点什么。

标签: javascript reactjs


【解决方案1】:

看看这是否适合你:

Working example on CodeSandbox

由于您已经在部分代码中使用了钩子,我已经使用钩子将您的类转换为功能组件(我的建议:学习钩子并忘记类组件)。

我已将value 属性添加到您的INITIAL_STATE,因此它将保留每个inputItem 的输入值。

完整代码:

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;

【讨论】:

    【解决方案2】:

    这里有一个代码框向您展示如何重置项目:https://codesandbox.io/s/romantic-heisenberg-93qi7

    我还给你留下了一条关于如何让它与你的 API 数据一起工作的注释,请参阅onChangeText() 中的评论

    问题在于输入不受您推断的状态控制。我们应该为您的 API 中的每个项目创建一个更新的对象,并为其提供一个 value 属性。

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

    购物车.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;
    

    Cart 组件可以基本保持不变,我们不需要将 props.items 传递给 useEffect() 依赖项。

    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;
    

    现在在Form 组件中,我们为每个输入提供一个值道具,该道具连接到我们最上面的父组件状态的项目。

    这就是重置值所需的全部内容。

    【讨论】:

    • 当我这样做时,它不允许我对输入​​字段值进行任何更改。因此,该值根本不会改变。
    • @user8306074 这很奇怪,我只是对您在沙箱中提供的代码进行了添加。在我提供给您的沙盒中,该功能是否未按您的预期执行?您的代码中可能还有更多我们看不到的内容?
    • 是的,还有更多内容,但这是一个单独的组件,不会影响这个组件。我看到了状态值,但 onChangeText 函数没有更新 Items 数组中的值。让我检查一下我是否正确复制了这些值。
    • 如果我使用这个逻辑,那么我不需要 itemvalues 数组?
    • @user8306074 很酷。我发现 itemsvalues 数组有一些奇怪的错误,所以我注释掉了。我不确定你用它做什么,但我可以帮你重建它。不过目前,此逻辑仅用于更新输入并重置它们。
    【解决方案3】:

    您想要管理未知数量的项目N 的状态,实现它的一种方法是管理包含所有状态的单个对象,例如,setValuesManager 管理 N 输入并单击 @987654327 @重置其状态:

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

    演示:

    【讨论】:

    • 所以,问题在于,我没有固定的项目值。就我而言,我有一个填充 Items 数组的函数,并为每个 Item 生成一个输入字段。所以,我不知道如何访问这些值。我将输入值保存为基于类的组件中的数组
    • 您可以添加任意数量的项目,正如我提到的state of unknown number N of items,这大致是您需要如何解决问题的想法。
    • 好吧,让我试试这个。
    • 我试过了,但是重置按钮似乎不起作用,它没有清除输入字段
    • 您查看了演示吗? codesandbox.io/s/os-q-56622204-jslwy?fontsize=14,你的代码有问题。正如 cmets 中所述,解决您的问题,您的代码不可读
    【解决方案4】:

    为了控制我认为是输入字段的子组件(项目)的值,您需要从其父组件传递它们的值。所以你的每个项目都会有一个item.value,它存储在父组件的状态中。

    这意味着在父组件中,您将能够定义一个方法来清除它存储在其状态中的所有项目值。 这可能看起来像

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

    您还需要编写您希望代码工作的标签类型,例如输入。

    因此,您共享的子组件的代码最终会是这样的:

    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 
    

    【讨论】:

    • 你能告诉我在这种情况下我应该如何设置父组件中的状态吗?
    • 您的意思是当您更改输入字段中的值时?因为它看起来不像您在任何地方定义 onChangeText。
    • 你的 onChangeText 需要是这样的:onChangeText = (itemIndex, newValue) =&gt; { this.setState({ Items: [...this.state.Items.slice(0, itemIndex), { ...this.state.Items[itemIndex], value: newValue }, ...this.state.Items.slice(itemIndex + 1) ] }
    • 然后在子组件中你会像这样使用它:{props.Items.map((item, index) =&gt; ( &lt;input ........ onChange={e =&gt; props.onChangeText(index, e.currentTarget.value)}
    • 就我而言,我有一个填充 Items 数组的函数,并为每个 Item 生成一个输入字段。所以,我不知道如何访问这些值。我将用户输入的输入值保存为基于类的组件(父组件)中的数组
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-30
    • 2020-02-24
    • 1970-01-01
    • 2017-10-20
    • 1970-01-01
    相关资源
    最近更新 更多