在React状态下难以设置对象的数组

时间:2020-05-24 21:35:56

标签: javascript arrays reactjs object state

我很困。我正在构建一个反应式闪存卡应用程序,并且在状态是对象数组时询问了一些有关设置状态的问题。我一直在研究不同的解决方案,而且看起来非常接近,但是似乎无法正常运行此代码。这是我的组件:

import React, { Component } from 'react'

export class TermForm extends Component {
    state = { 
        allTerms: [
        {
            term: '',
            def: ''
        },
        {
            term: '',
            def: ''
        },
        {
            term: '',
            def: ''
        },
        {
            term: '',
            def: ''
        },
        {
            term: '',
            def: ''
        },
        {
            term: '',
            def: ''
        },
        {
            term: '',
            def: ''
        },
        {
            term: '',
            def: ''
        },
        {
            term: '',
            def: ''
        },
        {
            term: '',
            def: ''
        }
    ]
}
    onChangeTerm = (event, index) => {
        event.preventDefault();
        this.setState({
            allTerms : [
            ...this.state.allTerms.splice(0,index) ,
            {
                ...this.state.allTerms[index],
                term: event.target.value
            },
            ...this.state.allTerms.splice(index+1) ,
            ]
        })
    }

    onChangeDef = (e, index) => {
        e.preventDefault();
        this.setState({
            allTerms : [
            ...this.state.allTerms.splice(0,index) ,
            {
                ...this.state.allTerms[index],
                def: e.target.value
            },
            ...this.state.allTerms.splice(index+1)
            ]
        })
    }

    render() {
        return (
            this.props.numberOfTerms.map((index) => (
                <div key={index}>
                    <input type="text" placeholder="TERM" value={this.state.allTerms.term} onChange={(event) => this.onChangeTerm(event, index)}></input>
                    <input type="text" placeholder="DEFINITION" value={this.state.allTerms.def} onChange={(e) => this.onChangeDef(e, index)}></input>
                </div>
            ))
        )
    }
}

export default TermForm

对于上下文,我的render方法中的return语句返回动态表单。基本上,根据用户要添加的术语数,呈现的表单可以有1到10行(每行包括一个用户想要添加的术语的输入字段,以及另一个定义的输入字段)的任意位置。对于术语和定义,我有单独的onChange事件。当我为第一个术语设置状态时(因此要通过onChangeTerm和onChangeDef函数进行设置),状态设置就很好了。但是,对于尝试在第一个卡片之后创建的任何数量的卡片,状态都会一团糟。通过查看chrome的react工具中的状态,我可以看到尝试创建第二张卡(以及第一张卡之后的任意数量的卡)后,该术语已设置完毕,但是当我输入定义时,它将清除该术语值。老实说,我很困惑。我以为问题出在我的onChange函数中的一个或两个中,但我似乎无法弄清楚问题出在哪里。任何帮助都将不胜感激。

1 个答案:

答案 0 :(得分:2)

我建议将数组存储在父组件中,并使用TermForm组件分别显示每个term + def。然后,当您更新一项/定义时,它会设置新状态并将信息传播到父项:https://codesandbox.io/s/pensive-morning-95cmx

我还渲染了应用程序状态以显示其正常工作;)还可以改善allTerms数组的创建。例如用循环填充它

// App.js
import React, { Component } from "react";
import "./styles.css";
import { TermForm } from "./TermForm";

export default class App extends Component {
  state = {
    allTerms: [
      {
        term: "",
        def: ""
      },
      {
        term: "",
        def: ""
      },
      {
        term: "",
        def: ""
      },
      {
        term: "",
        def: ""
      },
      {
        term: "",
        def: ""
      }
    ]
  };
  updateTermDef = (term, def, idx) => {
    const newTerms = [...this.state.allTerms];
    newTerms[idx] = {
      term,
      def
    };
    this.setState({ allTerms: newTerms });
  };
  render() {
    return (
      <div className="App">
        {this.state.allTerms.map((termDef, idx) => (
          <TermForm
            term={termDef.term}
            def={termDef.def}
            idx={idx}
            updateTermDef={(term, def) => this.updateTermDef(term, def, idx)}
          />
        ))}
        <h1>App state: </h1>
        {this.state.allTerms.map(termDef => (
          <>
            <span>
              {termDef.term} : {termDef.def}
            </span>
            <br />
          </>
        ))}
      </div>
    );
  }
}
//TermForm.js

import React, { Component } from "react";

export class TermForm extends Component {
  state = {
    term: this.props.term,
    def: this.props.def
  };

  render() {
    return (
      <div key={this.props.idx}>
        <input
          type="text"
          placeholder="TERM"
          value={this.state.term}
          onChange={event =>
            this.setState(
              { term: event.currentTarget.value },
              this.props.updateTermDef(this.state.term, this.state.def)
            )
          }
        />
        <input
          type="text"
          placeholder="DEFINITION"
          value={this.state.def}
          onChange={event =>
            this.setState(
              { def: event.currentTarget.value },
              this.props.updateTermDef(this.state.term, this.state.def)
            )
          }
        />
      </div>
    );
  }
}