如何设置映射输入的嵌套 JSON 数组对象的状态

IT技术 javascript arrays json reactjs object
2021-05-02 22:55:07

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

如何使用setState来更新每个的值字段onChange类别和字段使用map().

我可以在没有嵌套字段的情况下使其工作,但不能使用。感谢任何帮助。

JSON 文件

[{
    "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"
      }
}]

主程序

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;

分类.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;

项目.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;

4个回答

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

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

handleChange 函数

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

项目组件,添加类别和归档索引作为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;

演示

您的 JSON 无效。您还忘记检查是否list已经包含任何数据。

试试这个:

在您的handleChange方法中,请确保使用正确的 JSON 标记。你忘记了结尾]}

 this.setState({ 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"
        }
    ]}
  ]})

在您的Main的渲染方法中,检查列表是否为数组以及其长度是否大于 0。如果设置了非数组类型的值,这将防止任何渲染错误。

   {Array.isArray(this.state.list) && this.state.list.length < 0 && this.state.list.map(item => (
      <Category
        id={item.catName}
        name={item.catName}
        key={item.catName}
        list={item}
        handleChange={this.handleChange}
      />
    ))}

还要确保在主类的构造函数中设置一个空数组:

constructor(props) {
    super(props);
    this.state = {
      list: []
    };
 }

让我们从下往上开始

  1. 您需要通过将 is id 更改为 Item.js 为其父类别的 id 提供id={${name},${item.name}}添加 onClick 事件来清理以前的数据也会很好

  2. 需要提供的类别组件是项目组件的 id

  3. 然后在主组件中获得对 json 的正确访问权限后,您可以使用 createNewData 方法创建新对象

这是结果:

主程序

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

  createNewData = (mainAccess, property, value) => {
    let newData = sampleData;
    newData.forEach(category => {
      if (category["catName"] === mainAccess) {
        debugger;
        category["fields"].forEach(item => {
          if (item["name"] === property) {
            console.log(item["amount"]);
            item["amount"] = value;
          }
        });
      }
    });
    return newData
  };

  handleChange = e => {
    const propertyAccess = e.target.id.split(",");
    const newData = this.createNewData(propertyAccess[0],propertyAccess[1],e.target.value)
    this.setState({list:newData})
  };

  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;

项目.js

import React from "react";


const Item = ({ list, handleChange ,id}) => {

    return (
    <div className="item">
      <label className="label">{list.name}</label>
      <input
        name={list.name}
        id={id}
        className="input"
        type="text"
        onChange={handleChange}
        onClick={e=>e.target.value=""}
        value={list.amount}

      />
    </div>
  );
};

export default Item;

分类.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={`${name},${item.name}`}
          name={item.name}
          key={item.name}
          list={item}
          handleChange={handleChange}
        />
      ))}
    </div>
  );
};

export default Category;

更新您的代码如下

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, fieldName, catName) => {
    //get list from state
    const { list } = this.state

    //this returns the related item's index, I assume that all cats have a unique name, otherwise you should use unique values such as IDs
    const targetCatIndex = list.findIndex(item => item.catName === catName) 

    //find related field index
    const targetFieldIndex = list[targetCatIndex].fields.findIndex(item => item.name === fieldName)

    //update the field and assign to state
    list[targetCatIndex].fields[targetFieldIndex].amount = e.target.value

    this.setState({ list: list  });
  };

  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;



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}
          // pass field and cat referance with input event
          handleChange={(e, fieldName) => handleChange(e, fieldName, name) } 
        />
      ))}
    </div>
  );
};

export default Category;


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"
        //pass related field referance here
        onChange={(e) => handleChange(e, list.name)}
        value={list.amount}
      />
    </div>
  );
};

export default Item;

这是工作演示