Tout comme le bel avertissement que vous avez reçu, vous essayez de faire quelque chose qui est un anti-modèle dans React. C'est un non-non. React est conçu pour qu'un démontage se produise à partir d'une relation parent-enfant. Maintenant, si vous voulez qu'un enfant se démonte lui-même, vous pouvez simuler cela avec un changement d'état dans le parent qui est déclenché par l'enfant. Laissez-moi vous montrer en code.
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}
}
}
Il s'agit d'un exemple très simple, mais vous pouvez voir une manière approximative de transmettre une action au parent.
Ceci étant dit, vous devriez probablement passer par le magasin (action de distribution) pour permettre à votre magasin de contenir les données correctes lors du rendu.
J'ai créé des messages d'erreur ou d'état pour deux applications distinctes, qui sont toutes deux passées par le magasin. C'est la méthode préférée... Si vous le souhaitez, je peux poster du code sur la façon de le faire.
EDIT : Voici comment j'ai mis en place un système de notification en utilisant React/Redux/Typescript
Quelques points à noter tout d'abord. Il s'agit d'un script de type, vous devez donc supprimer les déclarations de type :)
J'utilise les paquets npm lodash pour les opérations, et classnames (cx alias) pour l'attribution des noms de classe en ligne.
La beauté de cette configuration est que j'utilise un identifiant unique pour chaque notification lorsque l'action la crée. (par exemple notify_id). Cet identifiant unique est un Symbol()
. Ainsi, si vous souhaitez supprimer une notification à tout moment, vous pouvez le faire car vous savez laquelle supprimer. Ce système de notification vous permettra d'en empiler autant que vous le souhaitez et elles disparaîtront lorsque l'animation sera terminée. Je me connecte à l'événement d'animation et lorsqu'il se termine, je déclenche un code pour supprimer la notification. J'ai également mis en place un délai de repli pour supprimer la notification au cas où le rappel de l'animation ne se déclenche pas.
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);
};
};
notification-réducteur.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;
};
app.tsx
dans le rendu de base de votre application, vous rendriez les notifications
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>
);
}
utilisateur-notification.tsx
classe de notification des utilisateurs
/*
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>
);
}
}
0 votes
Utilisez-vous Redux ?
1 votes
Pourquoi est-ce une exigence "Recevoir une erreur à travers ses props l'affichera mais j'aimerais un moyen de la fermer à partir de son propre code." ? L'approche normale consisterait à envoyer une action qui effacerait l'état d'erreur et serait ensuite fermée dans un cycle de rendu du parent, comme vous y avez fait allusion.
0 votes
J'aimerais offrir la possibilité de faire les deux en fait. En effet, il sera possible de le fermer comme vous l'avez expliqué, mais mon cas est "que faire si je veux aussi pouvoir le fermer de l'intérieur".