Javascript 动态添加表单字段——ReactJs

Javascript 动态添加表单字段——ReactJs,javascript,reactjs,Javascript,Reactjs,我的要求是动态添加表单字段。我可以在单击按钮+添加标题时动态添加表单组 在该表单组中,我有一个按钮+单击添加内容,新的输入元素应添加到该组中 我能够相应地修改JSON并记录相同的内容并更新状态。 但我的视图并没有按预期呈现 我们将非常感谢您的帮助 闪电战: /代码相同/ import React,{Component}来自'React'; 从'react dom'导入{render}; 从“reactstrap”导入{Form,FormGroup,Label,Progress,Button};

我的要求是动态添加表单字段。我可以在单击按钮+添加标题时动态添加表单组

在该表单组中,我有一个按钮+单击添加内容,新的输入元素应添加到该组中

我能够相应地修改JSON并记录相同的内容并更新状态。 但我的视图并没有按预期呈现

我们将非常感谢您的帮助

闪电战:

/代码相同/

import React,{Component}来自'React';
从'react dom'导入{render};
从“reactstrap”导入{Form,FormGroup,Label,Progress,Button};
从“./Hello”导入Hello;
导入“/style.css”;
常量byPropKey=(propertyName,value)=>()=>({
[propertyName]:值,
});
类应用程序扩展组件{
建造师(道具){
超级(道具);
此.state={
名称:'反应',
信息:“”,
ImageUrl:“”,
isUploading:false,
是的,
showProgress:false,
进展:0,
头像:“”,
参考:'WhitePapersItems',
formValid:false,
内容:[{标题:],内容:[{值:}]}]
};
this.AddContentBox=this.AddContentBox.bind(this);
this.handleChange=this.handleChange.bind(this);
this.AddContentInput=this.AddContentInput.bind(this);
}
AddContentBox(){
返回this.state.content.map((元素,i)=>(
标题
内容
{/*{this.AddContentInput}*/}
+添加内容
))
}
手柄更换(i,e){
const{Heading,value}=e.target;
让content=[…this.state.content];
content[i]={…content[i],[Heading]:value};
this.setState({content});
}
AddContentInput(索引,val){
log('addcontentinput-triggered',val,index);
const contents=this.state.content;
contents[index].Content.push({value:'});
this.setState({content:contents});
const item=this.state.content[index].content;
console.log('item',item)
返回item.map((元素,i)=>(
内容
))
//console.log(this.state)
//此.addContentField(索引);
}
添加标题(事件){
event.preventDefault();
this.setState(prevState=>({
内容:[…prevState.content,{标题:,内容:[{值:}]]
}))
this.AddContentBox();
}
render(){
返回(
问询处
this.setState(byPropKey('Information',event.target.value))}
type=“text”/>
{this.AddContentBox()}
+加标题
this.setState(byPropKey('ImageUrl',event.target.value))}/>
+添加白皮书项
);
}
}
render(,document.getElementById('root'));

此操作无法正常工作的原因是您正在直接修改此.state。React不会自动重新渲染,因为您没有告诉它状态已更改

您需要调用
this.setState()
来设置新状态

如果要添加到对象(例如
this.state.content
),则需要确保获取对象的副本(使用类似
..cloneDeep()
)的方法)以确保未修改现有对象

希望这是足够的解释,让你能够解决你的问题

更新: 您正在使用以下代码间接修改状态:

const contents=this.state.content;
contents[index].Content.push({value:'});


contents
是一个变量,它不是
this.state.content
的副本,它是对它的引用。因此,将一个值推入对象实际上是直接修改状态。我很抱歉在原始答案中没有将这一点说得更清楚为可能遇到这种情况的人回答我自己的问题

更新我的stackblitz:

我没有渲染所有内容字段,而是尝试只渲染一个

/代码在这里/

import React,{Component}来自'React';
从'react dom'导入{render};
从“reactstrap”导入{Form,FormGroup,Label,Progress,Button};
从“./Hello”导入Hello;
导入“/style.css”;
常量byPropKey=(propertyName,value)=>()=>({
[propertyName]:值,
});
类应用程序扩展组件{
建造师(道具){
超级(道具);
此.state={
名称:'反应',
信息:“”,
ImageUrl:“”,
isUploading:false,
是的,
showProgress:false,
进展:0,
头像:“”,
参考:'WhitePapersItems',
formValid:false,
内容:[{标题:],内容:[{值:}]}]
};
this.AddContentBox=this.AddContentBox.bind(this);
this.AddContentInput=this.AddContentInput.bind(this);
//this.addContentTextBox=this.addContentTextBox.bind(this);
}
AddContentInputFields(元素){
返回元素.Content.map(内容=>{
返回(
内容
);
})
}
AddContentBox(){
返回this.state.content.map((元素,i)=>(
标题
{this.AddContentInputFields(元素)}
+添加内容
))
}
手柄更换(i,e){
import React, { Component } from 'react';
import { render } from 'react-dom';
import { Form, FormGroup, Label, Progress,Button } from 'reactstrap';
import Hello from './Hello';
import './style.css';


const byPropKey = (propertyName, value) => () => ({
    [propertyName]: value,
  });
class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: 'React',
      Information:'',
      ImageUrl:'',
      isUploading: false,
      isUploaded: true,
      showProgress: false,
      progress: 0,
      avatarUrl:'',
      ref:'WhitePapersItems',
      formValid: false,
      content: [{Heading: "", Content: [{value:""}]}]
    };

        this.AddContentBox = this.AddContentBox.bind(this);
        this.handleChange = this.handleChange.bind(this);
        this.AddContentInput = this.AddContentInput.bind(this);
  }

  AddContentBox(){
        return this.state.content.map((element,i)=>(
            <div className="header-content" key={i} >
                <div className="heading-content-wrapper">
                <FormGroup>
                <Label className="set-label-pos upload-img" for="Heading">Heading</Label>
                <input className="form-control" onChange={this.handleChange.bind(this, i)}
                    type="text"/>
                </FormGroup>
                <FormGroup>
                <Label className="set-label-pos upload-img" for="Heading">Content</Label>
                <input className="form-control" onChange={this.handleChange.bind(this, i)}
                    type="text"/>
                </FormGroup>
                {/* {this.AddContentInput} */}
                <FormGroup>
                <Button color="success" onClick={this.AddContentInput.bind(this,i)}>+ Add Content</Button>
                </FormGroup>
            </div>
            </div>
        ))
    }

    handleChange(i, e) {
    const { Heading, value } = e.target;
      let content = [...this.state.content];
      content[i] = {...content[i], [Heading]: value};
      this.setState({ content });
   }

   AddContentInput(index, val){
        console.log('Add ContentInput triggered',val,index);       
        const contents = this.state.content;
        contents[index].Content.push({value:''});
        this.setState({content:contents});
        const item = this.state.content[index].Content;
        console.log('item', item)
        return item.map((element, i)=>(
            <FormGroup>
               <Label className="set-label-pos upload-img" for="Heading">Content</Label>
               <input className="form-control" type="text"/>
           </FormGroup>
       ))

        // console.log(this.state)
        // this.addContentField(index);
    }

     addHeading(event){
        event.preventDefault();
        this.setState(prevState => ({ 
            content: [...prevState.content, { Heading: "", Content: [{value:""}] }]
        }))
        this.AddContentBox();
   }

  render() {
    return (
      <div>


        <Form onSubmit={this.onSubmit}>

                <FormGroup>
                    <Label className="set-label-pos upload-img" for="Information">Information</Label>
                    <textarea className="form-control" rows="10" onChange={event => this.setState(byPropKey('Information', event.target.value))}
                        type="text"/>
                </FormGroup>
                {this.AddContentBox()}
                <div className="add-heading-button">
                    <Button color="primary" onClick={this.addHeading.bind(this)}>+ Add Heading</Button>
                </div>
                <FormGroup>
                <input type="hidden" value={this.state.ImageUrl} onChange={event => this.setState(byPropKey('ImageUrl', event.target.value))}/>
                </FormGroup>

                <Button className="btn btn-danger" size="lg" type="submit">+ Add White Papers Item</Button>
                </Form>

      </div>
    );
  }
}

render(<App />, document.getElementById('root'));
import React, { Component } from 'react';
import { render } from 'react-dom';
import { Form, FormGroup, Label, Progress,Button } from 'reactstrap';
import Hello from './Hello';
import './style.css';


const byPropKey = (propertyName, value) => () => ({
    [propertyName]: value,
  });
class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: 'React',
      Information:'',
      ImageUrl:'',
      isUploading: false,
      isUploaded: true,
      showProgress: false,
      progress: 0,
      avatarUrl:'',
      ref:'WhitePapersItems',
      formValid: false,
      content: [{Heading: "", Content: [{value:""}]}]
    };

        this.AddContentBox = this.AddContentBox.bind(this);
        this.AddContentInput = this.AddContentInput.bind(this);
        //this.addContentTextBox = this.addContentTextBox.bind(this);
  }

  AddContentInputFields(element) {
    return element.Content.map(content => {
      return (
        <FormGroup>
          <Label className="set-label-pos upload-img" for="Heading">Content</Label>
          <input className="form-control" type="text"/>
        </FormGroup>
      );
    })
  }

  AddContentBox(){
        return this.state.content.map((element,i)=>(
            <div className="header-content" key={i} >
                <div className="heading-content-wrapper">
                <FormGroup>
                <Label className="set-label-pos upload-img" for="Heading">Heading</Label>
                <input className="form-control" type="text"/>
                </FormGroup>
                { this.AddContentInputFields(element) }
                <FormGroup>
                <Button color="success" onClick={this.AddContentInput.bind(this,i)}>+ Add Content</Button>
                </FormGroup>
            </div>
            </div>
        ))
    }

    handleChange(i, e) {
    const { Heading, value } = e.target;
      let content = [...this.state.content];
      content[i] = {...content[i], [Heading]: value};
      this.setState({ content });
   }

   AddContentInput(index, val){
        console.log('Add ContentInput triggered',val,index);       
        const contents = _.cloneDeep(this.state.content);
        contents[index].Content.push({value:''});

        const item = contents[index].Content;
        console.log('item', item);
        this.setState({content:contents});
        //this.addContentTextBox(item);

    }

    // addContentTextBox(item){
    //   return item.map((element, i)=>(
    //         <FormGroup>
    //            <Label className="set-label-pos upload-img" for="Heading">Content</Label>
    //            <input className="form-control" type="text"/>
    //        </FormGroup>
    //    ));
    // }

     addHeading(event){
        event.preventDefault();
        this.setState(prevState => ({ 
            content: [...prevState.content, { Heading: "", Content: [{value:""}] }]
        }))
        this.AddContentBox();
   }

  render() {
    return (
      <div>


        <Form onSubmit={this.onSubmit}>

                <FormGroup>
                    <Label className="set-label-pos upload-img" for="Information">Information</Label>
                    <textarea className="form-control" rows="10" onChange={event => this.setState(byPropKey('Information', event.target.value))}
                        type="text"/>
                </FormGroup>
                {this.AddContentBox()}
                <div className="add-heading-button">
                    <Button color="primary" onClick={this.addHeading.bind(this)}>+ Add Heading</Button>
                </div>
                <FormGroup>
                <input type="hidden" value={this.state.ImageUrl} onChange={event => this.setState(byPropKey('ImageUrl', event.target.value))}/>
                </FormGroup>

                <Button className="btn btn-danger" size="lg" type="submit">+ Add White Papers Item</Button>
                </Form>

      </div>
    );
  }
}

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