首页 > 解决方案 > 打开一个通过单击在另一个组件中呈现的元素

问题描述

我正在使用一组语义 UI<Item>组件来列出一堆产品。我希望能够在<Item>单击时编辑产品的详细信息,并且我认为实现此目的的最佳方法是使用<Modal>组件。

我希望尽可能将所有内容拆分为可重用的组件。

import(注意:为了便于阅读,我故意省略了一些语句。)

应用程序.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>
    )
  }
}

因此,这将创建一个按钮,在呈现的任何地方都读取Got it<ModalExampleControlled />,并且该按钮会导致模式出现 - 很棒。

<Item>当单击产品列表中的元素之一(从而摆脱按钮)时,如何改为显示模式?

非常感谢您的宝贵时间。

克里斯

标签: reactjssemantic-ui-react

解决方案


您的问题是,目前模态在内部管理自己的状态。只要是这种情况并且没有其他组件可以访问该状态,就不能从外部触发模态组件。

有多种方法可以解决这个问题。最好的方法取决于您的应用程序是如何设置的。听起来最好的方法是用一个从高阶组件传递给模态的道具替换内部模态状态,该高阶组件还将打开/关闭函数传递给相关的子组件:

// 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 这样的模式可能有助于管理来自各处的不断变化的状态(例如模态)。不过,在您的情况下,这可能是 finde。


推荐阅读