如何在应用程序的任何位置设置反应模式以打开?

时间:2016-12-21 17:51:32

标签: reactjs redux react-modal

我对React比较陌生,但我正在尝试设置一个可以从任何地方打开的模态。这是我试图打开模态的方式:

class SearchResults extends React.Component {
  static propTypes = {
    status: React.PropTypes.string.isRequired,
    results: React.PropTypes.array.isRequired,
    onResultClick: React.PropTypes.func.isRequired
  }

  constructor(props) {
    super(props)
  }

  onUploadButtonClick() {
    console.log('here');
  }

  render () {
    const uploadButtonFn = this.onUploadButtonClick
    let childElements = [];

    childElements.unshift((
      <div className="upload-button-wrapper" key="upload-button">
        <button type="button" className="upload-button" onClick={uploadButtonFn}><span>+</span> Upload Your Vidy</button>
      </div>
    ))

    return (
      <div className='search-results'>
        <div className='inner-content'>
          {(() => {
            if (this.props.status === 'fetching') {
              return <h1>searching</h1>
            }

            if (this.props.status === 'ready') {
              return (
                <Masonry
                    className={'my-gallery-class'} // default ''
                    elementType={'div'} // default 'div'
                    disableImagesLoaded={false} // default false
                    updateOnEachImageLoad={false} // default false and works only if disableImagesLoaded is false
                >
                  {childElements}
                </Masonry>
              )
            }
          })()}
        </div>
        <GetMoreResult />
      </div>
    )
  }
}

export default SearchResults

这就是我试图打开模态的方式。我几乎肯定有更好的方法。我想,我正在使用redux。我继承了这个项目,所以我可能没有那么好。

非常感谢任何帮助。我想我需要在我的主布局中包含模态,但是我该如何触发它呢?

2 个答案:

答案 0 :(得分:2)

不确定您的代码是如何工作的,connect()在哪里?这里的任何地方都是我认为你想要使用redux的东西。这只是一个示例,因此您可以看到我们如何从任何其他组件显示模态,即使它不相关:

//action
const toggleModal = (isVisible) => ({
    type: "TOGGLE_MODAL",
    isVisible: isVisible
});

//reducer
export default (state={}, action) => {
    switch (action.type) {
        case "TOGGLE_MODAL":
            return {...state, isVisible: action.isVisible}
        default:
            return state;
    }
}

//connect() allows us to dispatch an action
class RandomClassElseWhereInApp extends connect()(React.Component {
    constructor(props) {
        super(props)
    }
    OpenModal = () => this.props.dispatch(toggleModal(true))
    render () {
        return (
        );
    }
})

//Gives us access to the store
const mapStateToProps = (state) => ({
    state.Modal.isVisible
});

//This is a smart component
class Modal extends connect(mapStateToProps)(React.Component {
  constructor(props) {
    super(props)
  }
  componentWillReceiveProps(nextProps) {
    //Empty string for display sets it to original value
    const display = "" ? this.props.isVisible : "none";

    this.setState({myModalStyle: {display: display}});
  }
  render () {
    return (
        <Popup style={this.state.myModalStyle}/>
    );
  }
})

//This is a dumb component
const Popup = ({style}) => (
    <div class="popup" style={style} />
);

答案 1 :(得分:1)

我们对此的解决方案如下:如果您使用的是redux和react-redux。

首先,制作一些动作创建者和一些redux状态来控制显示哪个模态。

// modal-action-reducer.js

export const ActionTypes = {
  CLOSE_MODAL: 'CLOSE_MODAL',
  OPEN_MODAL: 'OPEN_MODAL'
};

export const ActionCreators = {
  OpenModal = id => ({ type: ActionTypes.OPEN_MODAL, payload: { id } }),
  CloseModal: () => ({ type: ActionTypes.CLOSE_MODAL })
};

// this part of the state will be on something like `state.visibleModal`
export const reducer = (state = null, action) => {
  switch (action.type) {
    case ActionTypes.OPEN_MODAL:
      return action.payload.id;

    case ActionTypes.CLOSE_MODAL:
      return null;

    default:
      return state;
  }
};

然后创建一个更高阶的组件来装饰你的实际模态UI。

// ModalDecorator.jsx

import React from 'react';
import {connect} from 'react-redux';
import {ActionCreators} from './modal-action-reducer.js';

export default function ModalDecorator (modalId) {
  return function (WrappedModalComponent) {

    class WrapperComponent extends React.Component {
      render () {
        const {isVisible, ...otherProps} = this.props;
        return isVisible
          ? <WrappedModalComponent {...otherProps} />
          : <div style={{ display: 'none' }} >;

      } 
    }

    // get whether this modal is visible by checking the state from the reducer against the modal id
    const mapStateToProps = state => ({
      isVisible: state.visibleModal === modalId
    });

    // for convenience we can add a closeModal prop to all modals
    const mapDispatchToProps = dispatch => ({
      closeModal: () => dispatch(ActionCreators.CloseModal());
    });

    return connect(mapStateToProps, mapDispatchToProps)(WrapperComponent);
  }
}

然后在你的实际模态中:

// MyModal.jsx

import React from 'react';
import ModalDecorator from './ModalDecorator.jsx';

class MyModal extends React.Component {
  render () { /* Do your thing here */ }
}

export default ModalDecorator('my-modal-id')(MyModal);

这里需要注意的是,所有模态必须在某处进行渲染,因此为它们制作一个基本容器:

// ModalDeclarations.jsx
import MyModal from './MyModal.jsx';
import SomeOtherModal from './SomeOtherModaal.jsx';

const ModalDeclarations = () => (
  <div>
    <MyModal/>
    <SomeOtherModal/>
  </div>
);

export default ModalDeclarations;

在App.jsx中

import React from 'react'
import ModalDeclarations from './ModalDeclarations.jsx';

export default class App extends React.Component {
  render () {
    return (
      <div>
        {/* Other bits of your app here */}
        <ModalDeclarations />
      </div>
    );
  }
}

最后,我们可以在任何地方使用OpenModal动作创建器来打开任何模态。这是一个按钮,它将使用modalId从它的道具中打开模态。

// ModalButton.jsx

import React from 'react';
import {connect} from 'react-redux';
import {ActionCreators} from './modal-action-reducer.js';

const mapDispatchToProps = (dispatch, ownProps) => ({
  openModal: () => dispatch(ActionCreators.OpenModal(ownProps.modalId))
});

class ModalButton extends React.Component {
  render () {
    return (
      <div onClick={this.props.openModal} >
        {this.props.children}
      </div>
    )
  }
}

export default connect(null, mapDispatchToProps)(ModalButton);

ModalButton.propTypes = {
  modalId: React.PropTypes.string.isRequired
};