如何命名我的反应组件以容纳嵌套 JSON 中的元素?

Posted

技术标签:

【中文标题】如何命名我的反应组件以容纳嵌套 JSON 中的元素?【英文标题】:How do I name my react component to accommodate an element in my nested JSON? 【发布时间】:2020-06-10 23:31:38 【问题描述】:

我正在使用 React 16.13.0 我有以下组件 (src/containers/FormContainer.jsx) ...

class FormContainer extends Component 
  constructor(props) 
    super(props);

    this.state = 
      defaultCountry: 484,
      countries: [],
      provinces: [],
      newCoop: 
        name: '',
        type: '',
        ...
      ,


    ...
  render() 
    return (
        <form className="container-fluid" onSubmit=this.handleFormSubmit>

            <Input inputType='text'
                   title= 'Name'
                   name= 'name'
                   value=this.state.newCoop.name
                   placeholder = 'Enter cooperative name'
                   handleChange = this.handleInput

                   /> /* Name of the cooperative */

            <Input inputType='text'
                   title= 'Type'
                   name= 'type'
                   value=this.state.newCoop.type
                   placeholder = 'Enter cooperative type'
                   handleChange = this.handleInput

                   /> /* Type of the cooperative */

我的输入组件,src/components/Input.jsx,看起来像这样......

import React from 'react';

const Input = (props) => 
    return (
  <div className="form-group">
    <label htmlFor=props.name className="form-label">props.title</label>
    <input
      className="form-input"
      id=props.name
      name=props.name
      type=props.type
      value=props.value
      onChange=props.handleChange
      placeholder=props.placeholder
    />
  </div>
)


export default Input;

问题是我需要提交一个 POST 请求,其中“type”参数提交为以下 JSON ...


    "name": "1872",
    "type": 
        "name": "Coworking Space"
    ,
    ...

如何命名我的第二个输入字段(“类型”字段),以便我可以提交具有正确结构的 JSON?

编辑:句柄输入和提交函数...

  handleFormSubmit(e) 
    e.preventDefault();
    let coopData = this.state.newCoop;

    fetch('/coops/',
        method: "POST",
        body: JSON.stringify(coopData),
        headers: 
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        ,
      ).then(response => 
        response.json().then(data =>
          console.log("Successful" + data);
        )
    )
  
  handleClearForm() 
    // Logic for resetting the form
  
  handleInput(e) 
       let value = e.target.value;
       let name = e.target.name;
   this.setState( prevState => ( newCoop :
        ...prevState.newCoop, [name]: value
        
      ), () => console.log(this.state.newCoop))
  

【问题讨论】:

最简单的方法是更改​​handleFormSubmit 中的数据形状。你也可以分享那个代码吗? @bamse,将功能添加为我的问题的编辑 【参考方案1】:

有更多方法可以实现这一点,但我发现有两种方法可以实现

1。将 newCoop 保留在 POST 调用所需的结构中

this.state = 
  newCoop: 
    name: '',
    type: 
      name: ''
    
  

改变你给类型输入的值

<Input inputType='text'
  title= 'Type'
  name= 'type'
  value=this.state.newCoop.type.name
  placeholder = 'Enter cooperative type'
  handleChange = this.handleInput
/>

并调整this.handleInput 来处理这种情况:

您可能需要编写一个专用的handleTypeNameChange 函数 更改this.handleInput,使其能够处理这种情况

这取决于你的this.handleInput 功能 - 你能分享一下吗?

您输入的name 是html name 属性。不确定您是否在handleInput 中使用它。

2。保留表单,因为它是this.handleFormSubmit 中数据形状变化的句柄

this.handleFormSubmit = () => 
  const postData =  
    name: this.state.newCoop.name, 
    type: 
      name: this.state.newCoop.type
    
  
  // POST postData

同样,这取决于您的handleFormSubmit 代码。

希望对你有帮助!


关于选项 1 的更多详细信息:

我喜欢这种方法。 @heisenberg 为此提出了一个解决方案,但不能很好地扩展 - 它可以工作,但是添加更多字段会使该代码变得难以阅读和维护。

你可以: * 使用要更新的状态值的路径作为输入名称 * 在handleInput 中,您更新位于name 指定路径中的状态值

你可以这样写handleInput

import  set  from "lodash";
[...]
  handleInput = e => 
    let value = e.target.value;
    let name = e.target.name;
    const newCoop = set(this.state.newCoop, name, value);
    this.setState( newCoop );
  ;

我为此使用了 lodash 的 set。还有其他方法可以做到这一点 - 如果您真的不想要额外的依赖项,您甚至可以自己编写它。

为了让 newCoop.type.name 工作,您必须调整输入的名称

<input
  ...
  name="type.name" // <- use the path to the value you want to change
  value=this.state.newCoop.type.name
  ...
/>

Here 是一个带有工作示例的 Codesandbox。为简单起见,我使用了常规的 input,而不是组件。

【讨论】:

我喜欢您在此处的第一个建议中所说的话(保留 POST 调用的结构),因此我进行了更改以将类型值设置为“this.state.newCoop.type.name” ,但是当提交 POST 请求时,类型仍然以 'type: "myType"' 的形式提交,而实际需要提交的方式是 'type: name: "myType"'。【参考方案2】:

您必须在this.handleFormSubmit 方法中形成对象,这很容易,您只需根据您的要求形成对象。

handleFormSubmit = () => 
  //form json object as per required structure
  const formData=  
    name: this.state.newCoop.name, 
    type: 
      name: this.state.newCoop.type
    
  

 // then send formData in axios or fetch ajax method.

更新

我同意 @bamse 关于 scalibilty 的观点,现在我更改了解决方案以实现更好的缩放。

在此解决方案中,无需安装任何其他软件包。

您只需要再添加一个函数即可从输入组件中读取name,您可以在其中以点分格式分配name:"type.name"


    handleInput = (e) =>
      let self=this
      let value = e.target.value;
      let name = e.target.name;
      //update State
      this.setValue(self.state.newCoop,name,value) 
    

     setValue = (obj,is, value) => 
       if (typeof is == 'string')
         return this.setValue(obj,is.split('.'), value);
       else if (is.length==1 && value!==undefined)
         return this.setState(obj: obj[is[0]] = value);
       else if (is.length==0)
         return obj;
       else
         return this.setValue(obj[is[0]],is.slice(1), value);
      
输入组件更改:name= 'type.name'

----------------------------------------------END- ----------------------------------------------------

你没有在你的结构中得到 Object 的原因是,你在 INPUT 组件中给出了name= 'type'

所以当您在handleInput 方法中处理类型输入字段时,let name = e.target.name;"type"

当您在...prevState.newCoop, [name]: value 中设置状态时。这里[name]"type",这是newCoop 的关键。所以它会直接更新type 键。因为您在 INPUT 组件中传递了name= 'type'

【讨论】:

嗨@heisenberg,现在我的 fetch/Ajax 调用中有“body: JSON.stringify(coopData)”。我会继续对您创建的 formData JSON 使用那个“stringify(data)”方法吗? 嗨@Dave,是的,您必须在使用 fetch 时对正文中的数据进行字符串化,否则数据将以 [object] 格式发送。如果您使用 axios 调用,则不必对数据进行字符串化。与 fetch 相比,axios 调用很干净。您可以访问npmjs.com/package/axios。 谢谢。该表单似乎以正确的 JSON 格式提交,但是,我注意到的一件事是无法在地址字段中输入值,例如“街道”。每当我在那里输入时,字符都不会出现。它们显示在其他字段中,例如“名称”或“网站”。如果你有兴趣,这里是完整的代码——github.com/chicommons/maps/tree/master/client 嗨@Dave,我看过你的代码。几乎没有错误。我在 FormContainer.jsx 中做了一些更改。我提供了两种在状态中设置数据的方法。第二种方式是在 FormContainer_2.jsx 文件中。您可以浏览这两个 formContainer 文件。希望你喜欢。谢谢。该链接是这里的邮政编码drive.google.com/open?id=1UCQzk4oG3UnXGbCbTAEUz6jlUl-outag

以上是关于如何命名我的反应组件以容纳嵌套 JSON 中的元素?的主要内容,如果未能解决你的问题,请参考以下文章

动态嵌套反应形式:ExpressionChangedAfterItHasBeenCheckedError

如何通过反应 redux 中的唯一字符串切换状态?

在嵌套组件中反应组件道具

以编程方式从 Angular 2 中的 json 创建嵌套组件

如何使用验证编辑嵌套的反应式表单?

如何使用“文本输入”以“状态”更改和保存嵌套数据