繁体   English   中英

React ES6组件模式API

[英]React ES6 component modal API

我想基于https://github.com/reactjs/react-modal为对话框窗口创建组件API

我想用renderDOM渲染render组件,获取组件实例并调用模态的API,这的确意味着例如open(),close()等。

因此,更准确地说,我想使用组件的当前状态(例如API工作)而不使用道具。

我对所有模态都有简单的基类:

export class BaseModal extends Modal {

    constructor() {
        super();

        this.state = BaseModal._getInitState();          
    }

    static get style() {
        return {
            content: {
                top: '50%',
                left: '50%',
                right: 'auto',
                bottom: 'auto',
                marginRight: '-50%',
                transform: 'translate(-50%, -50%)'
            }
        };
    }

    open() {
        this.setState({isOpen: true});
    }

    close() {
        this.setState({isOpen: false});
    }

    render() {
        return this.state.isOpen ? (
            <div className="modal modal__{this.name}">

                <Modal isOpen={this.state.isOpen}
                       onRequestClose={this.close}
                       style={BaseModal.style}
                       contentLabel={this.getHeaderContent()}
                       parentSelector={BaseModal._getParentSelector}>

                    <button onClick={this.close}>X</button>

                    <div className="modal__body">
                        {this.getBodyContent()}
                    </div>

                    <div className="modal__footer">
                        {this.getFooterContent()}
                    </div>
                </Modal>
            </div>
        ) : null;
    }

    getHeaderContent() {
        throw new Error("Not implement in child class.");
    }

    getBodyContent() {
        throw new Error("Not implement in child class.");
    }

    getFooterContent() {
        throw new Error("Not implement in child class.");
    }   

    static _getInitState() {
        let state = {};
        state.isOpen = false;
    }       
}

现在我有子组件:

export class RecommendTripModal extends BaseModal {

    getHeaderContent() {
        return "Test modal dialog";      
    }

    getBodyContent() {
        return <p>Test modal body</p>;
    }

    getFooterContent() {
        return <p>Test modal footer</p>;
    }
}

好的,这很好,但是现在我想调用这样的名称:

let recommendedTripModal = ReactDOM.render(React.createElement(RecommendTripModal, null), document.querySelector("#modals")); 

//open dialog
recommendedTripModal.open();

但是现在是上下文问题。 因为this.state.isOpen具有RecommendTripModal上下文,所以状态为null。 有没有办法,如何用反应来解决这个问题? 这是可靠的方法吗? 还是我应该以其他方式创建所需的API?

感谢您的时间!

好的,让我们在这里进行更深入的探讨,最好的方法是使用React上下文和HoC魔术功能

Modal.js

import React from "react";
import PropTypes from "prop-types";
import { omit } from "lodash";

export class Modal extends React.Component {
  static contextTypes = {
    modalOpen: PropTypes.bool
  };

  static propTypes = {
    children: PropTypes.node
  };

  render() {
    if (!this.context.modalOpen) return null;

    return (
      <div>
        <h1>I am base modal title</h1>
        <div>{this.props.children}</div>
      </div>
    );
  }
}

export class ModalContext extends React.Component {
  static childContextTypes = {
    modalOpen: PropTypes.bool
  };

  static defaultProps = {
    onOpen: () => {},
    onClose: () => {}
  };

  static propTypes = {
    children: PropTypes.func.isRequired
  };

  constructor(...args) {
    super(...args);

    this.handleOpen = this.handleOpen.bind(this);
    this.handleClose = this.handleClose.bind(this);
  }

  state = {
    isOpen: false
  };

  getChildContext() {
    return {
      modalOpen: this.state.isOpen
    };
  }

  handleClose() {
    if (this.state.isOpen) {
      this.setState({ isOpen: false });
    }
  }

  handleOpen() {
    if (!this.state.isOpen) {
      this.setState({ isOpen: true });
    }
  }

  render() {
    const { identity, children } = this.props;
    return children({
      [identity]: {
        open: this.handleOpen,
        close: this.handleClose,
        isOpen: this.state.isOpen
      }
    });
  }
}

export default function modal(initialModalProps = {}) {
  return function(Component) {
    const componentName =
      Component.displayName || Component.name || "Component";

    return class extends React.Component {
      static displayName = `Modal(${componentName})`;

      static propTypes = {
        identity: PropTypes.string
      };

      static defaultProps = {
        identity: "modal"
      };

      render() {
        const { identity } = this.props;
        return (
          <ModalContext
            identity={identity}
            {...initialModalProps}
            {...this.props[identity]}
          >
            {modalProps => (
              <Component
                {...omit(this.props, identity, "identity")}
                {...modalProps}
              />
            )}
          </ModalContext>
        );
      }
    };
  };
}

HelloWorldModal.js

import React from "react";
import withModal, { Modal } from "./modal";

class HelloWorldModal extends React.Component {
  render() {
    const { modal } = this.props;
    return (
      <div>
        <button type="button" onClick={modal.open}>
          Open Modal
        </button>
        <button type="button" onClick={modal.close}>
          Close Modal
        </button>
        <Modal>Yeah! I am sample modal!</Modal>
      </div>
    );
  }
}

export default withModal()(HelloWorldModal);

如果你很懒,我准备了一个带有工作代码的codeandbox :)

https://codesandbox.io/s/2oxx2j4270?module=%2Fsrc%2FHelloWorldModal.js

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM