Как добавить несколько объектов в reactjs? - PullRequest
2 голосов
/ 20 марта 2020

Я хочу добавить новые объекты, когда пользователь нажимает на флажок. Например, когда пользователь нажимает на группу, он сохраняет данные {разрешение: {группа: ["1", "2"]}}. Если я нажму на topgroup, она будет хранить новые объекты с предыдущим

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

1st: Проблема в том, что я не могу объединить новый объект с предыдущим. Каждый раз, когда я нажимаю на группу или топгруппу, я вижу только один объект.

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

Вот мой кодовый ящик: https://codesandbox.io/s/stackoverflow-a-60764570-3982562-v1-0qh67

Ответы [ 4 ]

2 голосов
/ 20 марта 2020

Код много, потому что я добавил set и get, чтобы установить и получить состояние. Теперь вы можете сохранить путь к состоянию в permissionsKey и topGroupKey. Вы можете поместить get и set в отдельную библиотеку. js.

В этом примере строка в значительной степени не имеет состояния, и приложение сохраняет свое состояние. Таким образом, приложение может что-то делать со значениями, как только пользователь закончит проверять / снимать отметку с того, что ему нужно.

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>
1 голос
/ 20 марта 2020

Переписываю все обработчики.

Ошибка в вашем коде связана с использованием компонента antd Checkbox.Group с map в качестве child component, возможно, нам понадобится немного key для различения gui sh каждый из Row. Просто поместите их в один компонент, работающий без этого странного обновления состояния.


В качестве требования во время связи также добавляется total button.

И нам не нужно много штаты, сохраняйте данные из одного источника всегда лучшая практика.

enter image description here

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"));

Попробуйте онлайн :

Edit stackoverflow-a-60764570-3982562-v1

0 голосов
/ 20 марта 2020
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
0 голосов
/ 20 марта 2020

Пожалуйста, попробуйте это,

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

с помощью оператора распространения вы можете прекратить мутировать объект. Точно так же вы можете использовать object.assign вот так.

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

А также я бы предложил не вызывать setState при обратном вызове. Если вы хотите получить доступ к текущему состоянию, вы можете просто использовать текущее значение checked, которое вы получаете в самой функции.

так ваша функция становится,

onChange = value => checked => {
    this.setState({ checked });
    this.setState(prevState => {return { permission : { ...prevSatate.permission, { [value]: checked }}
}});
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...