我知道这个问题已经被问过好几次了,但大多数时候,解决办法是在家长身上处理这个问题,因为责任的流动只是在下降.然而,有时,您需要从某个组件的方法中删除该组件.

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}/>

在第What should I put here ?节中,我已经try 过:

ReactDOM.unmountComponentAtNode(ReactDOM.findDOMNode(this).parentNode);

警告:unmountComponentAtNode():您试图卸载的 node 由React呈现,不是顶级容器.相反,让父组件更新其状态并重新加载,以便删除此组件.

我应该在ErrorBox状态下复制传入的props ,并且只在内部操作它吗?

推荐答案

就像你收到的警告一样,你试图做一些反模式的事情.这是一个禁忌.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}
    }

}

这是一个非常简单的例子.但是你可以看到一个粗略的方法来传递给父母一个动作

也就是说,您可能应该通过存储(分派操作)来允许存储在渲染时包含正确的数据

我为两个不同的应用程序发送了错误/状态消息,它们都经过了store .这是首选的方法...如果你愿意,我可以发布一些代码来说明如何做到这一点.

EDIT: Here is how I set up a notification system using React/Redux/Typescript

首先要注意的几件事.这是在typescript中,因此您需要删除类型声明:)

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

这种设置的美妙之处在于,当操作创建通知时,我会 for each 通知使用一个唯一的标识符.(例如通知_id).这个唯一的ID是Symbol().通过这种方式,如果您想在任何时间点删除任何通知,您都可以,因为您知道要删除哪个通知.此通知系统将允许您堆叠任意数量的内容,动画完成后,这些内容将消失.我正在连接动画事件,当它结束时,我触发一些代码来删除通知.我还设置了一个回退超时来删除通知,以防动画回调没有触发.

通知操作.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);
    };
};

通知减速器.ts

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

应用程序.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>
    );
}

用户通知.tsx

用户通知类

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

Reactjs相关问答推荐

当我在React中使用类方法更新模型的状态时,它在严格模式下触发两次

如何在单击行中的图标时避免选中ionic 复选框?

使用下一步中的路由/导航不会立即加载路由

NextJS如何正确保存添加到购物车中的产品会话

在新屏幕上显示照片时出现问题-react

GitHub页面配置

useEffect firebase 清理功能如何工作?

我发送的 prop 的值不会改变.如果成功登录,导航栏中的 prop 必须为 true.我从后端得到 200 ok

如何将 MUI X 数据网格单元格方向更改为行级而不是列级?

使用 nextjs App Router 在动态客户端进行服务器端渲染

Formik onChange() 字段挂钩覆盖显示值和 Select 机制

使用带有搜索字符串的全局过滤器时如何在 React-Table 中进行精确匹配?

react - 警告:列表中的每个子元素都应该有一个独特的 keys props ,即使我已经设置了 keys

作为单个变量的 React 组件是否比 memoized 组件渲染得更快?

添加新行时自动打开可扩展表格(Antd 表格,ReactJS)

如何解决在 react.js 中找不到模块错误

如何从 extrareducer redux 更改对象中元素的值

如何在 React 中的 Material Ui 多选中设置默认值?

ReactJS:按钮启用禁用更改 colored颜色

Axios 删除在带有授权令牌的react js 中不起作用