如何设置映射输入的嵌套JSON数组对象的状态 [英] How to setState of nested JSON array object of mapped input

查看:49
本文介绍了如何设置映射输入的嵌套JSON数组对象的状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 JSON 文件,其中包含多个类别,每个类别都有一个名称,该名称带有一组具有各自名称和值的输入字段。

I have a JSON file with several categories, each category has a name with a set of input fields with their own name and value.

如何使用 setState 更新每个 onChange ?类别和字段使用 map()呈现。

How can I use setState to update the value fields of each onChange? The categories and fields are rendered using map().

我能够使它在没有嵌套字段的情况下工作,但在没有嵌套字段的情况下工作。感谢任何帮助。

I am able to make it work without the nested fields but not with. Appreciate any assistance.

[{
    "catName": "Category 1",
    "fields": [
      {
        "name": "field 1",
        "amount": "0"
      },
      {
        "name": "field 2",
        "amount": "0"
      }
    ]
  },
  {
    "catName": "Category 2",
    "fields": [
      {
        "name": "field 1",
        "amount": "0"
      },
      {
        "name": "field 2",
        "amount": "0"
      }
}]



Main.js



Main.js

import React, { Component } from "react";
import Category from "./Category";
import sampleData from "./sampleData";

class Main extends Component {
  constructor(props) {
    super(props);
    this.state = {
      list: sampleData
    };
  }

  handleChange = e => {
    this.setState({ ???  });
  };

  render() {
    return (
      <div>
        {this.state.list.map(item => (
          <Category
            id={item.catName}
            name={item.catName}
            key={item.catName}
            list={item}
            handleChange={this.handleChange}
          />
        ))}
      </div>
    );
  }
}

export default Main;



Category.js



Category.js

import React from "react";
import Item from "./Item";

const Category = ({ name, list, handleChange }) => {
  return (
    <div className="section">
      <h3>{name}</h3>
      {list.fields.map(item => (
        <Item
          id={item.name}
          name={item.name}
          key={item.name}
          list={item}
          handleChange={handleChange}
        />
      ))}
    </div>
  );
};

export default Category;



Item.js



Item.js

import React from "react";

const Item = ({ list, handleChange }) => {
  return (
    <div className="item">
      <label className="label">{list.name}</label>
      <input
        name={list.name}
        id={list.name}
        className="input"
        type="text"
        onChange={handleChange}
        value={list.amount}
      />
    </div>
  );
};

export default Item;


推荐答案

将类别和项目索引传递给您的 handleChange 函数。使用这些索引来更新数组中的正确项目。通过不做操作来避免状态突变

Pass the category and item index to your handleChange function. Use those index to update the correct item in the array. Avoid state mutation by not doing

// state mutation
this.state.list[categoryIndex].fields[fieldIndex].amount = e.target.value

handleChange函数

handleChange function

handleChange = (e, categoryIndex, itemIndex) => {

  const { list } = this.state;

  const fields = [...list[categoryIndex].fields.slice(0, itemIndex),
  Object.assign({}, list[categoryIndex].fields[itemIndex], { amount: e.target.value }),
  ...list[categoryIndex].fields.slice(itemIndex + 1)
  ]


  this.setState({
    list: [...list.slice(0, categoryIndex),
    Object.assign({}, list[categoryIndex], { fields }),
    ...list.slice(categoryIndex + 1)
    ]
  })
}

项目组件,添加类别和归档索引作为道具。

Item component, add category and filed index as props.

import React from "react";

const Item = ({ list, handleChange, categoryIndex, itemIndex, value }) => {
  return (
    <div className="item">
      <label className="label">{list.name}</label>
      <input
        name={list.name}
        id={list.name}
        className="input"
        type="text"
        value={value}
        onChange={(e) => handleChange(e, categoryIndex, itemIndex)}
      />
    </div>
  );
};

export default Item;

类别部分

import React from "react";
import Item from "./Item";

const Category = ({ name, list, handleChange, categoryIndex }) => {
  return (
    <div className="section">
      <h3>{name}</h3>
      {list.fields.map((item, index) => (
        <Item
          id={item.name}
          name={item.name}
          key={item.name}
          list={item}
          categoryIndex={categoryIndex}
          itemIndex={index}
          value={item.amount}
          handleChange={handleChange}
        />
      ))}
    </div>
  );
};

export default Category;

演示

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
<div id="root"></div>

<script type="text/babel">

const Item = ({ list, handleChange, categoryIndex, itemIndex, value }) => {
  return (
    <div className="item">
      <label className="label">{list.name}</label>
      <input
        name={list.name}
        id={list.name}
        className="input"
        type="text"
        value={value}
        onChange={(e) => handleChange(e, categoryIndex, itemIndex)}
      />
    </div>
  );
};

const Category = ({ name, list, handleChange, categoryIndex }) => {
  return (
    <div className="section">
      <h3>{name}</h3>
      {list.fields.map((item, index) => (
        <Item
          id={item.name}
          name={item.name}
          key={item.name}
          list={item}
          categoryIndex={categoryIndex}
          itemIndex={index}
          value={item.amount}
          handleChange={handleChange}
        />
      ))}
    </div>
  );
};

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      name: 'React',
      show: false,
      list: [
        {
          "catName": "Category 1",
          "fields": [
            {
              "name": "field 1",
              "amount": "0"
            },
            {
              "name": "field 2",
              "amount": "0"
            }
          ]
        },
        {
          "catName": "Category 2",
          "fields": [
            {
              "name": "field 1",
              "amount": "0"
            },
            {
              "name": "field 2",
              "amount": "0"
            }
          ]
        }
      ]
    };
  }

  handleChange = (e, categoryIndex, itemIndex) => {

    const { list } = this.state;

    const fields = [...list[categoryIndex].fields.slice(0, itemIndex),
    Object.assign({}, list[categoryIndex].fields[itemIndex], { amount: e.target.value }),
    ...list[categoryIndex].fields.slice(itemIndex + 1)
    ]


    this.setState({
      list: [...list.slice(0, categoryIndex),
      Object.assign({}, list[categoryIndex], { fields }),
      ...list.slice(categoryIndex + 1)
      ]
    })
  }
  
  show = () => {
    this.setState({
      show: true
    })
  }

  render() {
    return (
      <div>
        {this.state.list.map((item, index) => (
          <Category
            id={item.catName}
            name={item.catName}
            key={item.catName}
            categoryIndex={index}
            list={item}
            handleChange={this.handleChange}
          />
        ))}
        <br />
        <button onClick={this.show}>Show changes</button>
        {this.state.show &&
          <pre>
          {JSON.stringify(this.state.list, null, 4)}
          </pre>
        }
      </div>
    );
  }
}

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

这篇关于如何设置映射输入的嵌套JSON数组对象的状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆