【问题标题】:Proper way to build bootstrap modals and notifications in React JS?在 React JS 中构建引导模式和通知的正确方法?
【发布时间】:2017-10-26 02:48:07
【问题描述】:

我想在我的应用程序中使用模态和通知,并且来自使用旧的 jQuery Bootstrap,创建模态和通知非常容易,但现在我对如何使用 react 组件系统在虚拟 DOM 中实现这一点感到很困惑。

这是我认为在组件内的 React 中构建模式的标准反应方式:

Index/Router Component >
    Main Layout Component >
        {...Page Components... }
            {...Child Component}
                {<Modal /> or <Notification />}

这个问题是我不想经常在我的子组件中导入和创建&lt;Modal&gt;&lt;Notification /&gt; 组件,而可能只是调用一个实用函数,例如{app.notify({type: 'success', message: 'some message'})}app.modal({...customconfig}) 并拥有两者都在我的Main layout component 中定义,它通过任何子组件触发。

在这方面的任何帮助都会很棒,谢谢!

【问题讨论】:

    标签: javascript reactjs ecmascript-6


    【解决方案1】:

    您不需要将Modal 组件保留在层次结构中。你的Modal 组件应该是一个独立的组件,它需要适当的props 来决定需要显示的内容。例如

    <Modal message={"This is my modal"} showOkCancel={true} showYesNo={false} handleOkYes={()=>console.log("OK clicked")} handleCancelNo={()=>console.log("Cancel clicked"} />
    

    在上面的示例中,Modal 接受许多道具,这些道具将帮助它决定要显示的消息、要显示的按钮以及在所述按钮单击时需要采取的操作。

    这种组件可以驻留在组件层次结构之外,并且可以导入到任何需要显示模式的组件中。父组件只需要传递适当的道具来显示模式。

    希望这会有所帮助。

    【讨论】:

    • 我确实为我的问题找到了解决方案,它与您的回答有些相似。今晚将发布我的解决方案。效果很好。
    【解决方案2】:

    所以这是我解决这个问题的方法。

    首先是您希望如何构建模态和通知组件:

    {Index/Router Component}
        {Main Layout Component <Modal /> or <Notification />}
            {...Page Components... }
                {...Child Component calls app.modal({...config}) or app.notify(...config)}
    

    对于通知,我使用了一个名为 react-notification-system 的插件,对于模态,我只是自己编写的。

    这是我的代码:

    布局.js

    import React from "react";
    import {Link} from 'react-router';
    import NotificationSystem from 'react-notification-system';
    
    import AppHeader from "#/ui/header/AppHeader";
    import AppFooter from "#/ui/footer/AppFooter";
    
    import Modal from "#/ui/modals/modal/Modal";
    
    import "@/main.scss";
    import './layout.scss';
    
    
    export default class Layout extends React.Component {
        constructor(props) {
            super(props);
        }
    
        componentDidMount() {
            app.notify.clear = this.refs.notificationSystem.clearNotifications;
            app.notify = this.refs.notificationSystem.addNotification;
            app.modal = this.refs.modal.updateProps;
        }
    
        render() {
            return (
                <div class="app">
                    <div class="header">
                        <AppHeader page={this.props.location.pathname.replace('/', '')}/>
                    </div>
                    <div class="body">
                        {this.props.children}
                    </div>
                    <div class="footer">
                        <AppFooter />
                    </div>
    
                    <NotificationSystem ref="notificationSystem" style={false} />
                    <Modal ref="modal" />
                </div>
    
            );
        };
    }
    

    Modal.js

    import React from "react";
    import ReactDOM from 'react-dom';
    
    import SVGInline from "react-svg-inline";
    import {closeSvg} from '#/utils/Svg';
    
    export default class Modal extends React.Component {
        constructor(props) {
            super(props);
    
            this.state = {
                showHeader: true,
                showFooter: false,
                title: "",
                size: '',
                className: '',
                id: '',
                footerContent: null,
                showSubmitBtn: true,
                showCancelBtn: true,
                cancelBtnText: "Cancel",
                successBtnText: "Save Changes",
                onModalClose: () => {},
                showModal: false,
                html: () => {}
            }
    
            this.updateProps = this.updateProps.bind(this);
            this.hideModal = this.hideModal.bind(this);
        }
    
        componentWillMount() {
            var self = this;
    
            var $modal = $(ReactDOM.findDOMNode(this));
        }
    
        componentDidUpdate(prevProps, prevState) {
            if(this.state.showModal) {
                $('body').addClass('modal-open');
            } else {
                $('body').removeClass('modal-open');
            }
        }
    
        componentWillUnmount() {
            // $('body').removeClass("modal-open");
        }
    
        componentWillReceiveProps(nextProps) {
            console.log(nextProps);
        }
    
        updateProps(args) {
            let merged = {...this.state, ...args};
            this.setState(merged);
        }
    
        hideModal() {
            this.setState({
                showModal: false
            });
    
            this.state.onModalClose();
        }
    
        buildFooter() {
            if(this.props.footerContent) {
                return (
                    <div class="content">
                        {this.props.footerContent}
                    </div>
                )
            } else if(this.props.showCancelBtn && this.props.showSubmitBtn) {
                return (
                    <div class="buttons">
                        <button type="button" class="btn btn-default" data-dismiss="modal" onClick={this.props.onModalClose}>{this.props.cancelBtnText}</button>
                        <button type="button" class="btn btn-success">{this.props.successBtnText}</button>
                    </div>
                );
            } else if(this.props.showCancelBtn) {
                return (<button type="button" class="btn btn-default" data-dismiss="modal" onClick={this.props.onModalClose}>Close</button>);
            } else if(this.props.showSubmitBtn) {
                return (<button type="button" class="btn btn-success">Save changes</button>);
            }
        }
    
        render() {
            let {
                id,
                className,
                onModalClose,
                size,
                showHeader,
                title,
                children,
                showFooter,
                showModal,
                html
            } = this.state;
    
            return (
                <div class={`modal-wrapper`} >
                    {
                        showModal ?
                            <div class={`modal fade in ${className}`} role="dialog">
                                <div class="bg" ></div>
                                <div class={`modal-dialog ${size}`}>
                                    <div class="modal-content">
    
                                        { showHeader ?
                                            <div class="modal-header">
                                                <button type="button" class="close" data-dismiss="modal">
                                                    <SVGInline svg={closeSvg} />
                                                </button>
                                                <h4 class="modal-title">{ title }</h4>
                                            </div> : '' }
    
    
                                        <div class="modal-body" >
                                            {html()}
                                        </div>
    
                                        {  showFooter ?
                                            <div class="modal-footer">
                                                { this.buildFooter() }
                                            </div> : ''
                                        }
    
                                    </div>
                                </div>
                            </div>
                        : ''
                    }
                </div>
            );
        }
    }
    

    然后在您的任何子组件中,您可以在您的渲染函数中调用:

    app.notify({
        message: message,
        level: 'error'
    });
    

    app.modal({
        showModal: true,
        className: "fullscreen-image-modal",
        size: "modal-lg",
        html: () => {
            return (<img src={listingManager.LISTINGS_PATH + imgUrl} />);
        }
    })
    

    【讨论】:

      猜你喜欢
      • 2015-12-15
      • 2016-12-16
      • 2021-11-14
      • 2016-10-05
      • 2015-02-16
      • 2019-12-03
      • 1970-01-01
      • 2018-12-24
      • 1970-01-01
      相关资源
      最近更新 更多