Toast機能の追加
23436 ワード
バニラJavaScript->reactにASTを適用
バニラjavascriptでToastメッセージを実現する場合,domを実現するために
insertAdjacentElement, removeChild
などの手法を直接操作した.しかしreactでは、直接ドーム操作は行わないと聞いたので、他の方法で実現します.
実施方法
トーストメッセージリストをグローバル状態に管理して追加削除し、div.root要素に触れずにbodyにトーストコンテナを作成し、createPortalを使用してコンテナにトーストメッセージを貼り付けます.
keyword
function CreateToastPortal({ children }: PortalProps) {
const container = document.getElementById('toast-container');
let newContainer;
if (!container) {
const toast = document.createElement('div');
toast.setAttribute('id', 'toast-container');
newContainer = toast;
document.body.appendChild(newContainer);
} else {
newContainer = container;
}
return ReactDOM.createPortal(children, newContainer);
}
useContextを使用してメールのステータスを管理するconst [toasts, setToasts] = useState<ToastState[]>([]);
const createToast = useCallback((toast: Toast) => {
setToasts((prevToasts) => [...prevToasts, { id: nanoid(), ...toast }]);
}, []);
const hideToast = (toastId: string) => {
setToasts((prevToasts) => prevToasts.filter(({ id }) => id !== toastId));
};
<toastContext.Provider value={createToast}>
<CreateToastPortal>
{toasts.map((toast) => (
<ToastComponent key={toast.id} hideToast={hideToast} {...toast} />
))}
</CreateToastPortal>
{children}
</toastContext.Provider>
今は使いたいところに適切に情報状態を追加すればよい.以前はバニラで表現していました
import './toast.scss';
class Toast {
constructor(props) {
this.timeout = props?.timeout || 3000;
this.type = props?.type || 'success';
this.content = props?.content || '성공';
this.render();
}
createDom(tagName, attrs) {
const $dom = document.createElement(tagName);
for (const [key, value] of Object.entries(attrs)) {
$dom[key] = value;
}
return $dom;
}
render() {
const container = document.querySelector('.toast-container');
let newContainer;
if (!container) {
newContainer = this.createDom('div', {
className: 'toast-container',
});
document.body.appendChild(newContainer);
} else {
newContainer = container;
}
this.toast = this.createDom('div', {
className: 'toast',
});
newContainer.insertAdjacentElement('beforeend', this.toast);
this.toast.classList.add(this.type);
// setting content
this.toast.appendChild(
this.createDom('h4', {
innerText: this.content,
className: 'toast-content',
}),
);
// setting timer
this.toastTimeout.call(this, this.timeout);
this.progress = this.createDom('div', {
className: 'toast-progress',
});
this.toast.insertAdjacentElement('beforeend', this.progress);
this.progress.style.animation = `toast_progress ${this.timeout}ms linear forwards`;
}
toastTimeout(time) {
setTimeout(() => {
this.toast.classList.add('is-hiding');
setTimeout(() => {
this.hide();
}, 1500);
}, time);
}
hide() {
this.toast.parentNode?.removeChild(this.toast);
}
}
export default Toast;
// 사용법
// 1. 사용할 컴포넌트에서 import
// import Toast from '../../components/Toast/Toast';
// 2. 알림을 사용하고 싶은 곳에서
// new Toast({ content: '입력하고 싶은 메시지'})
// new Toast({ timeout: 3000, content: 'test', type: 'success' })
// new Toast({ timeout: 3000, content: 'test', type: 'fail' })
// new Toast()
// default timeout:3000, content: 성공, type: success
Reference
この問題について(Toast機能の追加), 我々は、より多くの情報をここで見つけました https://velog.io/@jiseong/Toast-기능-추가テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol