Как переключать динамически генерируемые раскрывающиеся списки с помощью индекса функций .map?

У меня есть массив, в котором для каждого элемента массива динамически генерируется раскрывающийся список. Прямо сейчас каждый раскрывающийся список использует один и тот же логический переключатель, поэтому все они открываются и закрываются в одно и то же время, как я могу заставить это работать индивидуально?

Здесь я сопоставляю каждый объект с индексом, а затем начинаю создавать раскрывающиеся списки:

{Object.keys(props.totalWorkload.options).map((item, i) => (
        <WorkloadOptions
          key={i}
          cnt={i}
          appendChoiceList={props.appendChoiceList}
          modalDropDown={props.modalDropDown}
          toggleDropDown={props.toggleDropDown}
          totalWorkloadOptions={props.totalWorkload.options[item]}
        />
      ))}

Когда компонент опций Drop Down создан, я передаю индекс функции:

<div>
    <Dropdown isOpen={props.modalDropDown} toggle={props.toggleDropDown.bind(props.cnt)}>
      <DropdownToggle caret>{props.totalWorkloadOptions.optionTitle}</DropdownToggle>
      <DropdownMenu>
        {props.totalWorkloadOptions.options.map(op => (
          // tslint:disable-next-line:no-invalid-this
          // tslint:disable-next-line:jsx-no-lambda
          <DropdownItem key={op} onClick= {() => props.appendChoiceList(props.totalWorkloadOptions.optionTitle, op)}>
            {op}
          </DropdownItem>
        ))}
      </DropdownMenu>
      <strong> {props.totalWorkloadOptions.optionDescription} </strong>
    </Dropdown>
    <br />
  </div>

Он прибудет к следующей функции и консоли зарегистрирует индекс, а затем установит соответствующее значение переключателя в массиве на true/false:

  toggleDropDown = (index: any) => {
    console.log('triggered!:' + index);
    let clicked = this.state.modalDropDownClicked;
    // tslint:disable-next-line:no-conditional-assignment
    if (clicked[index]=!clicked[index]){
      this.setState({ modalDropDownClicked: !this.state.modalDropDown[index] });
    }
  };

person Reacter23    schedule 07.11.2018    source источник


Ответы (1)


Я могу порекомендовать следующий шаблон для переключения динамически созданных элементов:

// Item.js

class Item extends React.Component {
  handleClick = () => {
    const { id, onClick } = this.props;
    onClick(id);
  }
  
  render() {
    const { isOpen } = this.props;
    
    return (
    <li><button onClick={this.handleClick}>{isOpen ? 'open' : 'closed'}</button></li>
    )
  }
}


// App.js

class App extends React.Component {
  static getDerivedStateFromProps(nextProps, prevState) {
    const { items } = nextProps;
    if (items !== prevState.prevPropsItems) {
      return { items, prevPropsItems: items };
    }
    return null;
  }
  
  state = {
    prevPropsItems: [],
    items: []
  }
  
  toggleItem = id => this.setState(prevState => {
    const items = prevState.items.map(item => {
      if (item.id === id) {
        return { ...item, isOpen: !item.isOpen }
      } else {
        return item;
      }
    });
    return { items }
  })
  
  render(){
    const { items } = this.state;
    
    return (<ul>
      {items.map(item => <Item key={item.id} id={item.id} onClick={this.toggleItem} isOpen={item.isOpen} />)}
    </ul>);
  }
}

// AppContainer.js

const itemsFromRedux = [
      { id: '1', isOpen: false },
      { id: '2', isOpen: false },
      { id: '3', isOpen: false },      
    ]

ReactDOM.render(<App items={itemsFromRedux} />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.1/umd/react-dom.development.js"></script>
    <div id="root"></div>

person gazdagergo    schedule 07.11.2018
comment
Спасибо, это большая помощь, я попытаюсь реализовать ее, массив не будет исправлен, так как он будет получен из GET, но это не должно иметь значения. - person Reacter23; 07.11.2018
comment
В этом случае элементы должны быть опорой приложения (при условии, что вы используете, например, избыточность). И используйте getDerivedStateFromProps для преобразования свойств в состояние всякий раз, когда они обновляются, чтобы вы могли обрабатывать их открытое состояние внутри компонента приложения. - person gazdagergo; 07.11.2018
comment
Я впервые слышу о GetDerivedStateFromProps, нужно ли это при реализации этих динамически генерируемых раскрывающихся списков? Поток моего кода здесь использует MapStateToProps для получения объекта с массивом объектов внутри, этот внутренний массив объектов повторяется для создания раскрывающихся списков, для каждого раскрывающегося списка должно быть создано n-е логическое значение для управления n-м раскрывающимся списком. вниз, внутренние объекты передают реквизит cnt, взятый из индекса .map, который передается компоненту, представляющему раскрывающийся список, который должен использовать это как номер индекса для передачи моей функции переключения - person Reacter23; 07.11.2018
comment
Прямо сейчас этот индекс из функции карты регистрируется как объект объекта, я хочу иметь возможность сравнить это с массивом логических значений и реализовать это так, как вы указали выше. - person Reacter23; 07.11.2018
comment
open и close — это состояния приложения, поэтому лучше использовать для него состояние, поскольку оно предназначено для него. Нет причин избегать обычного шаблона с использованием дополнительных логических значений и т. д. (если я правильно понял). Если вы хотите, чтобы я дополнил свой код частью getDerivedStateFromProps, это совсем не сложно. - person gazdagergo; 07.11.2018
comment
Не могли бы вы добавить его, и когда я смогу написать код позже, я попытаюсь реализовать его в своем коде по вашему шаблону? - person Reacter23; 07.11.2018
comment
Я добавил часть getDerivedStateFromProps. Однако в моей реализации, если элементы обновляются в редуксе, все логические значения возвращаются к ложным. Но вы можете настроить функцию getDer... так, чтобы она справилась с этим, чтобы открытые оставались открытыми. - person gazdagergo; 07.11.2018
comment
В настоящее время я пытаюсь просто заставить переключатель работать, а затем реализовать getDerivedStateFromProps, мне придется реорганизовать свой код, что может быть сложно, так как я использую Typescript, но плохо обновлю здесь, если смогу заставить его работать. - person Reacter23; 08.11.2018