首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在React/Redux中连接自定义通知系统?

如何在React/Redux中连接自定义通知系统?
EN

Stack Overflow用户
提问于 2017-05-23 17:39:28
回答 1查看 2.1K关注 0票数 1

我正在React/Redux中创建一个web应用程序,而且我对这个框架还很陌生。到目前为止,我已经创建了一个SignIn视图组件,它将调用signInUser操作创建者。此操作使用thunkuser-actions.js文件中解析/拒绝AJAX调用时分派适当的操作。

另外,我还创建了一个Notification视图组件。我有一个addNotification动作和notificationReducer。这可能会收到处理用户登录的通知以外的其他通知。

当AJAX请求被拒绝时,我希望Notification组件更新并显示错误。当signInUser操作被拒绝时,它会从addNotification文件中调用notification-actions.js操作。notificationReducer更新状态,Notification组件显示通知。

我试着在下面画出这幅图:

这是构建动作和组件之间的通信的好方法吗?有什么更好的做法我应该考虑吗?

(注意:我已经在我的项目中使用了react,redux,react路由器,thunk )。我想避免使用另一个库,这样我就不能更好地理解如何在React和Redux之间设置正确的东西。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-05-23 19:56:20

是的,这将是最好的方法。大约一年前,我创造了一个非常类似的东西。我就是这么安排的..。

有几件事要先注意..。这是在类型记录中,所以您需要删除类型声明:)

我使用npm包lodash进行操作,classnames (cx别名)用于内联类名分配。

此设置的优点是,在操作创建每个通知时,我都使用唯一的标识符。(如notify_id)。这个唯一的ID是一个Symbol()。这样,如果您想在任何时间点删除任何通知,您可以这样做,因为您知道要删除哪一个通知。这个通知系统将允许你堆叠你想要的多少,当动画完成时,它们就会消失。我正在链接到动画事件,当它结束时,我会触发一些代码来删除通知。我还设置了一个后备超时以删除通知,以防动画回调没有触发。

notification-actions.ts

代码语言:javascript
运行
复制
import { USER_SYSTEM_NOTIFICATION } from '../constants/action-types';

interface IDispatchType {
    type: string;
    payload?: any;
    remove?: Symbol;
}

export const notifySuccess = (message: any, duration?: number) => {
    return (dispatch: Function) => {
        dispatch({ type: USER_SYSTEM_NOTIFICATION, payload: { isSuccess: true, message, notify_id: Symbol(), duration } } as IDispatchType);
    };
};

export const notifyFailure = (message: any, duration?: number) => {
    return (dispatch: Function) => {
        dispatch({ type: USER_SYSTEM_NOTIFICATION, payload: { isSuccess: false, message, notify_id: Symbol(), duration } } as IDispatchType);
    };
};

export const clearNotification = (notifyId: Symbol) => {
    return (dispatch: Function) => {
        dispatch({ type: USER_SYSTEM_NOTIFICATION, remove: notifyId } as IDispatchType);
    };
};

notification-reducer.ts

代码语言:javascript
运行
复制
const defaultState = {
    userNotifications: []
};

export default (state: ISystemNotificationReducer = defaultState, action: IDispatchType) => {
    switch (action.type) {
        case USER_SYSTEM_NOTIFICATION:
            const list: ISystemNotification[] = _.clone(state.userNotifications) || [];
            if (_.has(action, 'remove')) {
                const key = parseInt(_.findKey(list, (n: ISystemNotification) => n.notify_id === action.remove));
                if (key) {
                    // mutate list and remove the specified item
                    list.splice(key, 1);
                }
            } else {
                list.push(action.payload);
            }
            return _.assign({}, state, { userNotifications: list });
    }
    return state;
};

app.tsx

在应用程序的基本呈现中,您将呈现通知。

代码语言:javascript
运行
复制
render() {
    const { systemNotifications } = this.props;
    return (
        <div>
            <AppHeader />
            <div className="user-notify-wrap">
                { _.get(systemNotifications, 'userNotifications') && Boolean(_.get(systemNotifications, 'userNotifications.length'))
                    ? _.reverse(_.map(_.get(systemNotifications, 'userNotifications', []), (n, i) => <UserNotification key={i} data={n} clearNotification={this.props.actions.clearNotification} />))
                    : null
                }
            </div>
            <div className="content">
                {this.props.children}
            </div>
        </div>
    );
}

user-notification.tsx

用户通知类

代码语言:javascript
运行
复制
/*
    Simple notification class.

    Usage:
        <SomeComponent notifySuccess={this.props.notifySuccess} notifyFailure={this.props.notifyFailure} />
        these two functions are actions and should be props when the component is connect()ed

    call it with either a string or components. optional param of how long to display it (defaults to 5 seconds)
        this.props.notifySuccess('it Works!!!', 2);
        this.props.notifySuccess(<SomeComponentHere />, 15);
        this.props.notifyFailure(<div>You dun goofed</div>);

*/

interface IUserNotifyProps {
    data: any;
    clearNotification(notifyID: symbol): any;
}

export default class UserNotify extends React.Component<IUserNotifyProps, {}> {
    public notifyRef = null;
    private timeout = null;

    componentDidMount() {
        const duration: number = _.get(this.props, 'data.duration', '');

        this.notifyRef.style.animationDuration = duration ? `${duration}s` : '5s';


        // fallback incase the animation event doesn't fire
        const timeoutDuration = (duration * 1000) + 500;
        this.timeout = setTimeout(() => {
            this.notifyRef.classList.add('hidden');
            this.props.clearNotification(_.get(this.props, 'data.notify_id') as symbol);
        }, timeoutDuration);

        TransitionEvents.addEndEventListener(
            this.notifyRef,
            this.onAmimationComplete
        );
    }
    componentWillUnmount() {
        clearTimeout(this.timeout);

        TransitionEvents.removeEndEventListener(
            this.notifyRef,
            this.onAmimationComplete
        );
    }
    onAmimationComplete = (e) => {
        if (_.get(e, 'animationName') === 'fadeInAndOut') {
            this.props.clearNotification(_.get(this.props, 'data.notify_id') as symbol);
        }
    }
    handleCloseClick = (e) => {
        e.preventDefault();
        this.props.clearNotification(_.get(this.props, 'data.notify_id') as symbol);
    }
    assignNotifyRef = target => this.notifyRef = target;
    render() {
        const {data, clearNotification} = this.props;
        return (
            <div ref={this.assignNotifyRef} className={cx('user-notification fade-in-out', {success: data.isSuccess, failure: !data.isSuccess})}>
                {!_.isString(data.message) ? data.message : <h3>{data.message}</h3>}
                <div className="close-message" onClick={this.handleCloseClick}>+</div>
            </div>
        );
    }
}

user-notify.less

代码语言:javascript
运行
复制
@white: #FFFFFF;
@green: #58ba68;
@charcoal: #404040;
@warning-red: #e63c3c;

.user-notify-wrap {
    position: fixed;
    bottom: 1rem;
    left: 1rem;
    min-width: 20rem;
    z-index: 2000;

    .user-notification {
        position: relative;
        width: 100%;
        text-align: center;
        color: @white;
        background-color: @charcoal;

        margin-top: 1rem;
        padding: 1rem 2.5rem 1rem 1rem;
        border-radius: 3px;
        box-shadow: 0 0 2px rgba(0,0,0,.12),0 2px 4px rgba(0,0,0,.24);

        opacity: 0;

        transition: all .5s;

        &:first-child {
            margin-top: 0;
        }

        &.success {
            background-color: @green;
        }
        &.failure {
            /*background-image: linear-gradient(to right, @faded-red, @purple);*/
            background-color: @warning-red;
        }

        &.fade-in-out {
            animation: fadeInAndOut forwards;
        }

        &.hidden {
            height: 0;
            margin: 0;
            padding: 0;
            display: none;
            visibility: hidden;
        }

        .close-message {
            position: absolute;
            top: 50%;
            right: 1rem;
            font-size: 2rem;
            color: @white;
            cursor: pointer;
            transform: rotate(45deg) translate(-50%, -50%);
        }
        * {
            color: @white;
            font-size: 1.125rem;
        }
        h1, h2, h3, h4, h5, h6 {
            color: @white !important;
            margin: 0 !important;
            font-family: Lato;
            padding: 0 1rem;
        }
    }
}

@keyframes fadeInAndOut {
    0% { opacity: 0; }
    10% { opacity: 1; }
    90% { opacity: 1; }
    99% { opacity: 0; }
    100% { display: none !important; visibility: none !important; height: 0 !important; width: 0 !important; }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44141590

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档