Откройте <Modal>, нажав на элемент, отображаемый в другом компоненте. - PullRequest
0 голосов
/ 26 июня 2018

Я использую группу компонентов Semantic UI <Item> для составления списка продуктов. Я хочу иметь возможность редактировать сведения о продукте при нажатии на <Item>, и я подумал, что лучший способ добиться этого - использовать компонент <Modal>.

Я хочу, чтобы все, где это возможно, было разбито на компоненты многократного использования.

(Примечание. Я специально пропустил некоторые операторы import, чтобы их было легче читать.)

App.js

import { ProductList } from 'components';

const App = () => (
  <Segment>
    <Item.Group divided>
      <ProductList/>
    </Item.Group>
  </Segment>
)

export default App;

компоненты / ProductList.js

import { ProductListItem } from '../ProductListItem';

export default class ProductList extends Component {
  constructor() {
    super()
    this.state = { contents: [] }
  }

  componentDidMount() {
    var myRequest = new Request('http://localhost:3000/contents.json');
    let contents = [];

    fetch(myRequest)
    .then(response => response.json())
    .then(data => {
      this.setState({ contents: data.contents });
    });

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

  render() {
    return (
      this.state.contents.map(content => {
        return (
          <ProductListItem
            prod_id={content.prod_id}
            prod_description={content.prod_description}
            category_description={content.category_description}
          />
        );
      })
    )
  }
}

компоненты / ProductListItem.js

export default class ProductListItem extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <Item key={`product-${this.props.prod_id}`} as='a'>
        <Item.Content>
          <Item.Header>{this.props.prod_description}</Item.Header>
          <Item.Description>
            <p>{this.props.prod_description}</p>
          </Item.Description>
        </Item.Content>
      </Item>
    )
  }
}

Все это прекрасно работает, и список продуктов отображается как следует.

Я также создал базовый модальный компонент, используя один из примеров в Модальных документах :

компоненты / ModalExampleControlled.js

export default class ModalExampleControlled extends Component {
  state = { modalOpen: false }

  handleOpen = () => this.setState({ modalOpen: true })
  handleClose = () => this.setState({ modalOpen: false })

  render() {
    return (
      <Modal
        trigger={<Button onClick={this.handleOpen}>Show Modal</Button>}
        open={this.state.modalOpen}
        onClose={this.handleClose}
        size='small'
      >
        <Header icon='browser' content='Cookies policy' />
        <Modal.Content>
          <h3>This website uses cookies etc ...</h3>
        </Modal.Content>
        <Modal.Actions>
          <Button color='green' onClick={this.handleClose}>Got it</Button>
        </Modal.Actions>
      </Modal>
    )
  }
}

Таким образом, это создаст кнопку, которая будет читать Понял везде, где <ModalExampleControlled /> отображается, и кнопка вызывает модальное появление - отлично.

Как вместо этого заставить модал появляться при нажатии на один из <Item> элементов в списке товаров (таким образом избавиться от кнопки)?

Большое спасибо за ваше время.

Chris

1 Ответ

0 голосов
/ 26 июня 2018

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

Существуют различные способы решения этой проблемы. Лучший способ зависит от того, как настроено ваше приложение. Похоже, лучший способ - это заменить внутреннее модальное состояние пропеллером, который передается модальному из компонента более высокого порядка, который также передает функции открытия / закрытия соответствующим дочерним элементам:

// Modal.js
export default class ModalExampleControlled extends Component {
  render() {
    return (
      { this.props.open ?
      <Modal
        open={this.props.open}
        onClose={this.props.handleClose}
        size='small'
      >
        <Header icon='browser' content='Cookies policy' />
        <Modal.Content>
          <h3>This website uses cookies etc ...</h3>
        </Modal.Content>
        <Modal.Actions>
          <Button color='green' onClick={this.props.handleClose}>Got it</Button>
        </Modal.Actions>
      </Modal>
      : null }
    )
  }
}

// App.js
import { ProductList } from 'components';

class App extends Component  {
    handleOpen = () => this.setState({ open: true })
    handleClose = () => this.setState({ open: false })
    render(){
        return(
           <Segment>
             <Item.Group divided>
               <ProductList/>
             </Item.Group>
             <Modal open={this.state.open} closeModal={() => this.handleClose()}}
          </Segment>
        )
    }
}

export default App;

Имейте в виду, что этот код является примерным и не закончен. Основная идея заключается в следующем: вам нужно передать управление родительскому компоненту высшего уровня, который выше всех других компонентов, которым необходим доступ к нему. Таким образом, вы можете при необходимости передавать функции открытия / закрытия дочерним элементам и контролировать модальное состояние.

Это может быть громоздким, если есть много такого прохождения. Если ваше приложение станет очень сложным, оно станет вопросом управления состоянием. Когда много шаблонов, таких как Redux, это может помочь управлять изменяющимися состояниями (например, модальными) повсюду. В вашем случае это может быть окончательно, однако.

...