简体   繁体   English

如何在reactjs中添加多个对象?

[英]how to add multiple objects in reactjs?

I want to add new Objects when user click on checkbox.当用户单击复选框时,我想添加新对象。 For example , When user click on group , it will store data {permission:{group:["1","2"]}}.例如,当用户点击 group 时,它会存储数据 {permission:{group:["1","2"]}}。 If I click on topgroup , it will store new objects with previous one如果我单击 topgroup ,它将存储与前一个对象相同的新对象

{permission:{group:["1","2"]},{topGroup:["1","2"]}}. 

1st : The problem is that I can not merge new object with previous one .第一:问题是我无法将新对象与以前的对象合并。 I saw only one objects each time when I click on the group or topgroup.每次单击组或顶部组时,我只看到一个对象。

  onChange = value => checked => {
    this.setState({ checked }, () => {
      this.setState(prevState => {
        Object.assign(prevState.permission, { [value]: this.state.checked });
      });
    });
  };

  <CheckboxGroup
            options={options}
            value={checked}
            onChange={this.onChange(this.props.label)}
   />

Here is my codesanbox: https://codesandbox.io/s/stackoverflow-a-60764570-3982562-v1-0qh67这是我的 codesanbox: https ://codesandbox.io/s/stackoverflow-a-60764570-3982562-v1-0qh67

It is a lot of code because I've added set and get to set and get state.这是很多代码,因为我添加了 set 和 get 来设置和获取状态。 Now you can store the path to the state in permissionsKey and topGroupKey .现在您可以将状态路径存储在permissionsKeytopGroupKey You can put get and set in a separate lib.js.您可以将 get 和 set 放在单独的 lib.js 中。

In this example Row is pretty much stateless and App holds it's state, this way App can do something with the values once the user is finished checking/unchecking what it needs.在这个例子中,Row 几乎是无状态的,App 保持它的状态,这样一旦用户完成检查/取消检查它需要的值,App 就可以对这些值做一些事情。

 const Checkbox = antd.Checkbox; const CheckboxGroup = Checkbox.Group; class Row extends React.Component { isAllChecked = () => { const { options, checked } = this.props; return checked.length === options.length; }; isIndeterminate = () => { const { options, checked } = this.props; return ( checked.length > 0 && checked.length < options.length ); }; render() { const { options, checked, onChange, onToggleAll, stateKey, label, } = this.props; //all data and behaviour is passed by App return ( <div> <div className="site-checkbox-all-wrapper"> <Checkbox indeterminate={this.isIndeterminate()} onChange={e => onToggleAll(e.target.checked, stateKey) } checked={this.isAllChecked()} > Check all {label} </Checkbox> <CheckboxGroup options={options} value={checked} onChange={val => { onChange(stateKey, val); }} /> </div> </div> ); } } //helper from https://gist.github.com/amsterdamharu/659bb39912096e74ba1c8c676948d5d9 const REMOVE = () => REMOVE; const get = (object, path, defaultValue) => { const recur = (current, path) => { if (current === undefined) { return defaultValue; } if (path.length === 0) { return current; } return recur(current[path[0]], path.slice(1)); }; return recur(object, path); }; const set = (object, path, callback) => { const setKey = (current, key, value) => { if (Array.isArray(current)) { return value === REMOVE ? current.filter((_, i) => key !== i) : current.map((c, i) => (i === key ? value : c)); } return value === REMOVE ? Object.entries(current).reduce((result, [k, v]) => { if (k !== key) { result[k] = v; } return result; }, {}) : { ...current, [key]: value }; }; const recur = (current, path) => { if (path.length === 1) { return setKey( current, path[0], callback(current[path[0]]) ); } return setKey( current, path[0], recur(current[path[0]], path.slice(1)) ); }; return recur(object, path, callback); }; class App extends React.Component { state = { permission: { group: [] }, topGroup: [], some: { other: [{ nested: { state: [] } }] }, }; permissionsKey = ['permission', 'group']; //where to find permissions in state topGroupKey = ['topGroup']; //where to find top group in state someKey = ['some', 'other', 0, 'nested', 'state']; //where other group is in state onChange = (key, value) => { //use set helper to set state this.setState(set(this.state, key, arr => value)); }; isIndeterminate = () => !this.isEverythingChecked() && [ this.permissionsKey, this.topGroupKey, this.someKey, ].reduce( (result, key) => result || get(this.state, key).length, false ); toggleEveryting = e => { const checked = e.target.checked; this.setState( [ this.permissionsKey, this.topGroupKey, this.someKey, ].reduce( (result, key) => set(result, key, () => checked ? this.plainOptions.map(({ value }) => value) : [] ), this.state ) ); }; onToggleAll = (checked, key) => { this.setState( //use set helper to set state set(this.state, key, () => checked ? this.plainOptions.map(({ value }) => value) : [] ) ); }; isEverythingChecked = () => [ this.permissionsKey, this.topGroupKey, this.someKey, ].reduce( (result, key) => result && get(this.state, key).length === this.plainOptions.length, true ); plainOptions = [ { value: 1, name: 'Apple' }, { value: 2, name: 'Pear' }, { value: 3, name: 'Orange' }, ]; render() { return ( <React.Fragment> <h1>App state</h1> {JSON.stringify(this.state)} <div> <Checkbox indeterminate={this.isIndeterminate()} onChange={this.toggleEveryting} checked={this.isEverythingChecked()} > Toggle everything </Checkbox> </div> {[ { label: 'group', stateKey: this.permissionsKey }, { label: 'top', stateKey: this.topGroupKey }, { label: 'other', stateKey: this.someKey }, ].map(({ label, stateKey }) => ( <Row key={label} options={this.plainOptions} // use getter to get state selected value // for this particular group checked={get(this.state, stateKey)} label={label} onChange={this.onChange} //change behaviour from App onToggleAll={this.onToggleAll} //toggle all from App //state key to indicate what state needs to change // used in setState in App and passed to set helper stateKey={stateKey} /> ))} </React.Fragment> ); } } ReactDOM.render(<App />, document.getElementById('root'));
 <link href="https://cdnjs.cloudflare.com/ajax/libs/antd/4.0.3/antd.css" rel="stylesheet"/> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/antd/4.0.3/antd.js"></script> <div id="root"></div>

I rewrite all the handlers.我重写了所有的处理程序。

The bug in your code is located on the usage of antd Checkbox.Group component with map as a child component , perhaps we need some key to distinguish each of the Row .你代码中的bug是在使用antd Checkbox.Group组件和map作为child component ,可能我们需要一些key来区分每一Row Simply put them in one component works without that strange state update.只需将它们放在一个组件中即可,无需那种奇怪的状态更新。


As the demand during communication, the total button is also added.作为交流时的需求,还增加了total button

And, we don't need many states, keep the single-source data is always the best practice.而且,我们不需要很多状态,保持单源数据始终是最佳实践。

在此处输入图片说明

import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Checkbox } from "antd";

const group = ["group", "top"];
const groupItems = ["Apple", "Pear", "Orange"];

const CheckboxGroup = Checkbox.Group;

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      permission: {}
    };
  }
  UNSAFE_componentWillMount() {
    this.setDefault(false);
  }
  setDefault = fill => {
    const temp = {};
    group.forEach(x => (temp[x] = fill ? groupItems : []));
    this.setState({ permission: temp });
  };
  checkLength = () => {
    const { permission } = this.state;
    let sum = 0;
    Object.keys(permission).forEach(x => (sum += permission[x].length));
    return sum;
  };

  /**
   * For total
   */
  isTotalIndeterminate = () => {
    const len = this.checkLength();
    return len > 0 && len < groupItems.length * group.length;
  };
  onCheckTotalChange = () => e => {
    this.setDefault(e.target.checked);
  };
  isTotalChecked = () => {
    return this.checkLength() === groupItems.length * group.length;
  };

  /**
   * For each group
   */
  isIndeterminate = label => {
    const { permission } = this.state;
    return (
      permission[label].length > 0 &&
      permission[label].length < groupItems.length
    );
  };
  onCheckAllChange = label => e => {
    const { permission } = this.state;
    const list = e.target.checked ? groupItems : [];
    this.setState({ permission: { ...permission, [label]: list } });
  };
  isAllChecked = label => {
    const { permission } = this.state;
    return !groupItems.some(x => !permission[label].includes(x));
  };

  /**
   * For each item
   */
  isChecked = label => {
    const { permission } = this.state;
    return permission[label];
  };
  onChange = label => e => {
    const { permission } = this.state;
    this.setState({ permission: { ...permission, [label]: e } });
  };

  render() {
    const { permission } = this.state;
    console.log(permission);
    return (
      <React.Fragment>
        <Checkbox
          indeterminate={this.isTotalIndeterminate()}
          onChange={this.onCheckTotalChange()}
          checked={this.isTotalChecked()}
        >
          Check all
        </Checkbox>
        {group.map(label => (
          <div key={label}>
            <div className="site-checkbox-all-wrapper">
              <Checkbox
                indeterminate={this.isIndeterminate(label)}
                onChange={this.onCheckAllChange(label)}
                checked={this.isAllChecked(label)}
              >
                Check all
              </Checkbox>
              <CheckboxGroup
                options={groupItems}
                value={this.isChecked(label)}
                onChange={this.onChange(label)}
              />
            </div>
          </div>
        ))}
      </React.Fragment>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("container"));

Try it online:在线试一下:

编辑 stackoverflow-a-60764570-3982562-v1

Please try this,请试试这个,

onChange = value => checked => {
    this.setState({ checked }, () => {
         this.setState(prevState => {
            permission : { ...prevSatate.permission , { [value]: this.state.checked }}
          });
        });
      };

by using spread operator you can stop mutating the object.通过使用扩展运算符,您可以停止改变对象。 same way you can also use object.assign like this.同样的方式你也可以像这样使用 object.assign 。

this.setState(prevState => {
        permission : Object.assign({} , prevState.permission, { [value]: this.state.checked });
      });

And also i would suggest not to call setState in a callback.而且我建议不要在回调中调用 setState 。 If you want to access the current state you can simply use the current checked value which you are getting in the function itself.如果您想访问当前状态,您可以简单地使用您在函数本身中获得的当前checked值。

so your function becomes ,所以你的功能变成,

onChange = value => checked => {
    this.setState({ checked });
    this.setState(prevState => {return { permission : { ...prevSatate.permission, { [value]: checked }}
}});
};
Try the following
//Inside constructor do the following
this.state = {checkState:[]} 
this.setChecked = this.setChecked.bind(this);
//this.setChecked2 = this.setChecked2.bind(this);


//Outside constructor but before render()
setChecked(e){
         this.setState({
             checkState : this.state.checkState.concat([{checked: e.target.id + '=>' + e.target.value}])
             //Id is the id property for a specific(target) field

         });
}

//Finally attack the method above.i.e. this.setChecked to a form input.

Hope it will address your issues

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM