当前位置: 首页 > 面试题库 >

如何在React / Redux / Typescript通知消息中从自身上卸下,取消渲染或删除组件

蒋茂
2023-03-14
问题内容

我知道这个问题已经被问过几次了,但是在大多数情况下,解决方法是在父级中解决这个问题,因为责任流只是在下降。但是,有时您需要使用一种方法杀死组件。我知道我无法修改其道具,并且如果我开始添加布尔值作为状态,那么对于一个简单的组件而言,它将会变得非常混乱。这是我要实现的目标:一个小的错误框组件,带有一个“
x”将其关闭。通过其道具接收到错误将显示该错误,但是我想一种从其自己的代码中关闭该错误的方法。

class ErrorBoxComponent extends React.Component {

  dismiss() {
    // What should I put here?
  }

  render() {
    if (!this.props.error) {
      return null;
    }

    return (
      <div data-alert className="alert-box error-box">
        {this.props.error}
        <a href="#" className="close" onClick={this.dismiss.bind(this)}>&times;</a>
      </div>
    );
  }
}


export default ErrorBoxComponent;

我会在父组件中这样使用它:

<ErrorBox error={this.state.error}/>

在本节中 我应该在这里放什么? ,我已经尝试过:

ReactDOM.unmountComponentAtNode(ReactDOM.findDOMNode(this).parentNode);
这在控制台中引发了一个不错的错误:

警告:unmountComponentAtNode():您尝试卸载的节点是由React渲染的,不是顶级容器。而是让父组件更新其状态并重新渲染,以删除此组件。

我是否应该在ErrorBox状态下复制传入的道具,并仅在内部对其进行操作?


问题答案:

就像您收到的警告一样,您正在尝试做React中的反模式。这是禁忌。React旨在使父母与孩子之间的关系摆脱困境。现在,如果您希望孩子自行卸载,则可以通过由孩子触发的父状态更改来模拟此情况。让我向您展示代码。

class Child extends React.Component {
    constructor(){}
    dismiss() {
        this.props.unmountMe();
    } 
    render(){
        // code
    }
}

class Parent ...
    constructor(){
        super(props)
        this.state = {renderChild: true};
        this.handleChildUnmount = this.handleChildUnmount.bind(this);
    }
    handleChildUnmount(){
        this.setState({renderChild: false});
    }
    render(){
        // code
        {this.state.renderChild ? <Child unmountMe={this.handleChildUnmount} /> : null}
    }

}

这是一个非常简单的例子。但您可以看到一种粗略的方法来将动作传递给父项

话虽这么说,您可能应该遍历商店(调度操作)以允许商店在呈现时包含正确的数据

我已经为两个单独的应用程序完成了错误/状态消息,它们都通过了商店。这是首选方法…如果您愿意,我可以发布一些有关如何执行此操作的代码。

首先要注意的事情。这是在打字稿中,所以您需要删除类型声明:)

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

此设置的好处是,在操作创建通知时,我为每个通知使用唯一的标识符。(例如notify_id)。此唯一ID是Symbol()。这样,如果您想随时删除任何通知,就可以,因为您知道要删除的通知。此通知系统将使您可以堆叠任意数量的对象,动画完成后它们将消失。我迷上了动画事件,完成后我触发了一些代码来删除通知。我还设置了一个后备超时以删除通知,以防动画回调不触发。

notification-actions.ts

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);
    };
};

通知减少器

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

在应用程序的基本渲染中,您将渲染通知

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>
    );
}

用户通知

用户通知类

/*
    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>
        );
    }
}


 类似资料:
  • 我有一个组件类,我正在使用react-redux将redux存储连接到该组件类,但是当我尝试将该组件传递到connect函数时,出现了一个错误。 以下是我正在使用的每个接口(redux发出的调度除外): IFileItemProps:组件将使用的所有类型 IFilePassedProps:这些是从父组件传递到组件的道具,所以我没有看到呈现的组件元素的键入问题。 IFileItemReduxStat

  • 对于从Spring Boot API发送的每个查询,我都会收到以下警告消息,并希望将其从日志中删除。 我正在使用RestHighLevelClient。根据Elasticsearch的说法,这可以通过迁移到他们最近推出的Elasticsearch Java API客户端来解决。然而,这将需要很长时间才能让我们做出这样的改变。 Elasticsearch版本是7.14.1,不幸的是,我们无法升级它。

  • 问题内容: 一个典型的Redis聊天示例将如下所示(仅举一个这样的示例,请参见https://github.com/emrahayanoglu/Socket.io- Redis-RealTime-Chat- Example/blob/master/chatServer.js ): 但是,这里的问题是,当“断开连接”时,侦听器仍然处于连接状态。控制台将继续打印出。如果要检查的事件列表,他们仍然会发现

  • 问题内容: 我正在尝试从某个门户网站获取交易状态,并且在我的Java应用程序中使用了以下chrome设置, 超时从渲染器接收消息:60.000 并且所有待处理的交易都已超时。 会话信息:headless chrome = 68.0.3440.75 驱动程序信息: chromedriver = 2.38 (0) 平台= Linux 2.6.32-696.23.1.el6.x86_64 x86_64)

  • 简介 除了 发送邮件 Laravel 还支持通过多种频道发送通知,包括邮件、短信 (通过 Nexmo), 以及 Slack。通知还能存到数据库,这样就能在网页界面上显示了。 通常情况下,通知应该是简短、有信息量的消息来通知用户你的应用发生了什么。举例来说,如果你在编写一个在线交易应用,你应该会通过邮件和短信频道来给用户发送一条 「账单已付」 的通知。 创建通知 Laravel 中一条通知就是一个类

  • 对用户发送通知时,如果配置了推送证书,将会产生推送,推送消息为通知内容,extras字段内容为通知的频道标识,如: { "extras":{"channel":"news:comment"} } 未读通知数量检查 通知列表 读取通知 标记通知阅读 标记所有通知已读 数据解析 未读通知数量检查 HEAD /user/notifications 本接口可用于消息分组显示的客户端,可以提前得到未